diff options
Diffstat (limited to 'lib/libc/gen')
301 files changed, 53125 insertions, 0 deletions
diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc new file mode 100644 index 000000000000..4d064d18d36e --- /dev/null +++ b/lib/libc/gen/Makefile.inc @@ -0,0 +1,590 @@ +# machine-independent gen sources +.PATH: ${LIBC_SRCTOP}/${LIBC_ARCH}/gen ${LIBC_SRCTOP}/gen ${SRCTOP}/etc + +CONFS+= group master.passwd shells +CONFSMODE_master.passwd= 600 +CONFSPACKAGE= runtime + +SRCS+= \ + __pthread_mutex_init_calloc_cb_stub.c \ + __xuname.c \ + _once_stub.c \ + _pthread_stubs.c \ + _rand48.c \ + _spinlock_stub.c \ + _thread_init.c \ + aio_read2.c \ + aio_write2.c \ + alarm.c \ + arc4random.c \ + arc4random-compat.c \ + arc4random_uniform.c \ + assert.c \ + basename.c \ + basename_compat.c \ + cap_sandboxed.c \ + check_utility_compat.c \ + clock.c \ + clock_getcpuclockid.c \ + closedir.c \ + confstr.c \ + cpuset_alloc.c \ + cpuset_free.c \ + crypt.c \ + ctermid.c \ + daemon.c \ + devname.c \ + devname-compat11.c \ + dirfd.c \ + dirname.c \ + dirname_compat.c \ + disklabel.c \ + dlfcn.c \ + drand48.c \ + dup3.c \ + elf_utils.c \ + erand48.c \ + err.c \ + errlst.c \ + eventfd.c \ + exec.c \ + exect.c \ + fdevname.c \ + fdopendir.c \ + feature_present.c \ + fmtcheck.c \ + fmtmsg.c \ + fnmatch.c \ + fpclassify.c \ + frexp.c \ + fstab.c \ + ftok.c \ + fts.c \ + fts-compat.c \ + fts-compat11.c \ + ftw.c \ + ftw-compat11.c \ + getbootfile.c \ + getbsize.c \ + getcap.c \ + getcwd.c \ + getdomainname.c \ + getentropy.c \ + getgrent.c \ + getgrouplist.c \ + gethostname.c \ + getloadavg.c \ + getlogin.c \ + getmntinfo.c \ + getmntinfo-compat11.c \ + getnetgrent.c \ + getosreldate.c \ + getpeereid.c \ + getprogname.c \ + getpwent.c \ + getttyent.c \ + getusershell.c \ + getutxent.c \ + getvfsbyname.c \ + glob.c \ + glob-compat11.c \ + initgroups.c \ + inotify.c \ + isatty.c \ + isinf.c \ + isnan.c \ + jrand48.c \ + kqueue1.c \ + lcong48.c \ + libc_dlopen.c \ + libc_interposing_table.c \ + lrand48.c \ + memalign.c \ + memfd_create.c \ + mrand48.c \ + nftw.c \ + nftw-compat11.c \ + nice.c \ + nlist.c \ + nrand48.c \ + opendir.c \ + opendir2.c \ + pause.c \ + pmadvise.c \ + popen.c \ + posix_spawn.c \ + psignal.c \ + pututxline.c \ + pw_scan.c \ + raise.c \ + readdir.c \ + readdir-compat11.c \ + readpassphrase.c \ + rewinddir.c \ + scandir.c \ + scandir_b.c \ + scandir-compat11.c \ + sched_getaffinity.c \ + sched_setaffinity.c \ + seed48.c \ + seekdir.c \ + semctl.c \ + setdomainname.c \ + sethostname.c \ + setjmperr.c \ + setmode.c \ + setproctitle.c \ + setprogname.c \ + sig2str.c \ + siginterrupt.c \ + siglist.c \ + signal.c \ + sigsetops.c \ + sleep.c \ + srand48.c \ + statvfs.c \ + stringlist.c \ + strtofflags.c \ + sysconf.c \ + sysctl.c \ + sysctlbyname.c \ + sysctlnametomib.c \ + syslog.c \ + telldir.c \ + termios.c \ + time.c \ + times.c \ + timespec_get.c \ + timespec_getres.c \ + timezone.c \ + tls.c \ + ttyname.c \ + ttyslot.c \ + ualarm.c \ + uexterr_format.c \ + uexterr_gettext.c \ + ulimit.c \ + uname.c \ + unvis-compat.c \ + usleep.c \ + utime.c \ + utxdb.c \ + valloc.c \ + wordexp.c + +.if ${COMPILER_FEATURES:Mblocks} +CFLAGS.fts.c= -fblocks +CFLAGS.glob.c= -fblocks +.endif + +CFLAGS.arc4random.c= -I${SRCTOP}/sys -I${SRCTOP}/sys/crypto/chacha20 + +CFLAGS.sysconf.c= -I${SRCTOP}/contrib/tzcode + +CFLAGS.dlfcn.c= ${RTLD_HDRS} +CFLAGS.tls.c= ${RTLD_HDRS} + +.PATH: ${SRCTOP}/contrib/libc-pwcache +SRCS+= pwcache.c pwcache.h + +.PATH: ${SRCTOP}/contrib/libc-vis +CFLAGS+= -I${SRCTOP}/contrib/libc-vis +SRCS+= unvis.c vis.c + +MISRCS+=modf.c + +CANCELPOINTS_SRCS=sem.c sem_new.c +.for src in ${CANCELPOINTS_SRCS} +SRCS+=cancelpoints_${src} +CLEANFILES+=cancelpoints_${src} +cancelpoints_${src}: ${LIBC_SRCTOP}/gen/${src} .NOMETA + ln -sf ${.ALLSRC} ${.TARGET} +.endfor + +SYM_MAPS+=${LIBC_SRCTOP}/gen/Symbol.map + +# machine-dependent gen sources +.sinclude "${LIBC_SRCTOP}/${LIBC_ARCH}/gen/Makefile.inc" + +MAN+= alarm.3 \ + arc4random.3 \ + basename.3 \ + cap_rights_get.3 \ + cap_sandboxed.3 \ + check_utility_compat.3 \ + clock.3 \ + clock_getcpuclockid.3 \ + confstr.3 \ + ctermid.3 \ + daemon.3 \ + devname.3 \ + directory.3 \ + dirname.3 \ + dl_iterate_phdr.3 \ + dladdr.3 \ + dlinfo.3 \ + dllockinit.3 \ + dlopen.3 \ + dup3.3 \ + err.3 \ + exec.3 \ + feature_present.3 \ + fmtcheck.3 \ + fmtmsg.3 \ + fnmatch.3 \ + fpclassify.3 \ + frexp.3 \ + ftok.3 \ + fts.3 \ + ftw.3 \ + getbootfile.3 \ + getbsize.3 \ + getcap.3 \ + getcontext.3 \ + getcwd.3 \ + getdiskbyname.3 \ + getdomainname.3 \ + getentropy.3 \ + getfsent.3 \ + getgrent.3 \ + getgrouplist.3 \ + gethostname.3 \ + getloadavg.3 \ + getmntinfo.3 \ + getnetgrent.3 \ + getosreldate.3 \ + getpass.3 \ + getpeereid.3 \ + getprogname.3 \ + getpwent.3 \ + getttyent.3 \ + getusershell.3 \ + getutxent.3 \ + getvfsbyname.3 \ + glob.3 \ + initgroups.3 \ + isgreater.3 \ + ldexp.3 \ + makecontext.3 \ + modf.3 \ + nice.3 \ + nlist.3 \ + pause.3 \ + popen.3 \ + posix_spawn.3 \ + posix_spawn_file_actions_addopen.3 \ + posix_spawn_file_actions_init.3 \ + posix_spawnattr_getflags.3 \ + posix_spawnattr_getpgroup.3 \ + posix_spawnattr_getschedparam.3 \ + posix_spawnattr_getschedpolicy.3 \ + posix_spawnattr_init.3 \ + posix_spawnattr_getsigdefault.3 \ + posix_spawnattr_getsigmask.3 \ + psignal.3 \ + pwcache.3 \ + raise.3 \ + rand48.3 \ + readpassphrase.3 \ + rtld_get_var.3 \ + scandir.3 \ + sem_destroy.3 \ + sem_getvalue.3 \ + sem_init.3 \ + sem_open.3 \ + sem_post.3 \ + sem_timedwait.3 \ + sem_wait.3 \ + setjmp.3 \ + setmode.3 \ + setproctitle.3 \ + siginterrupt.3 \ + signal.3 \ + sigsetops.3 \ + statvfs.3 \ + stringlist.3 \ + strtofflags.3 \ + sysconf.3 \ + sysctl.3 \ + syslog.3 \ + tcgetpgrp.3 \ + tcgetsid.3 \ + tcgetwinsize.3 \ + tcsendbreak.3 \ + tcsetattr.3 \ + tcsetpgrp.3 \ + tcsetsid.3 \ + time.3 \ + times.3 \ + timespec_get.3 \ + timespec_getres.3 \ + ttyname.3 \ + ualarm.3 \ + ucontext.3 \ + ulimit.3 \ + uname.3 \ + unvis.3 \ + utime.3 \ + valloc.3 \ + vis.3 \ + wordexp.3 + +MLINKS+=arc4random.3 arc4random_buf.3 \ + arc4random.3 arc4random_uniform.3 +MLINKS+=ctermid.3 ctermid_r.3 +MLINKS+=daemon.3 daemonfd.3 +MLINKS+=devname.3 devname_r.3 +MLINKS+=devname.3 fdevname.3 +MLINKS+=devname.3 fdevname_r.3 +MLINKS+=directory.3 closedir.3 \ + directory.3 dirfd.3 \ + directory.3 fdclosedir.3 \ + directory.3 fdopendir.3 \ + directory.3 opendir.3 \ + directory.3 readdir.3 \ + directory.3 readdir_r.3 \ + directory.3 rewinddir.3 \ + directory.3 seekdir.3 \ + directory.3 telldir.3 +MLINKS+=dlopen.3 fdlopen.3 \ + dlopen.3 dlclose.3 \ + dlopen.3 dlerror.3 \ + dlopen.3 dlfunc.3 \ + dlopen.3 dlsym.3 \ + dlopen.3 dlvsym.3 +MLINKS+=err.3 err_set_exit.3 \ + err.3 err_set_file.3 \ + err.3 errc.3 \ + err.3 errx.3 \ + err.3 verr.3 \ + err.3 verrc.3 \ + err.3 verrx.3 \ + err.3 vwarn.3 \ + err.3 vwarnc.3 \ + err.3 vwarnx.3 \ + err.3 warnc.3 \ + err.3 warn.3 \ + err.3 warnx.3 +MLINKS+=exec.3 execl.3 \ + exec.3 execle.3 \ + exec.3 execlp.3 \ + exec.3 exect.3 \ + exec.3 execv.3 \ + exec.3 execvP.3 \ + exec.3 execvp.3 \ + exec.3 execvpe.3 +MLINKS+=fpclassify.3 finite.3 \ + fpclassify.3 finitef.3 \ + fpclassify.3 isfinite.3 \ + fpclassify.3 isinf.3 \ + fpclassify.3 isnan.3 \ + fpclassify.3 isnormal.3 +MLINKS+=frexp.3 frexpf.3 \ + frexp.3 frexpl.3 +MLINKS+=fts.3 fts_children.3 \ + fts.3 fts_close.3 \ + fts.3 fts_open.3 \ + fts.3 fts_read.3 \ + fts.3 fts_set.3 \ + fts.3 fts_set_clientptr.3 \ + fts.3 fts_get_clientptr.3 \ + fts.3 fts_get_stream.3 +MLINKS+=ftw.3 nftw.3 +MLINKS+=getcap.3 cgetcap.3 \ + getcap.3 cgetclose.3 \ + getcap.3 cgetent.3 \ + getcap.3 cgetfirst.3 \ + getcap.3 cgetmatch.3 \ + getcap.3 cgetnext.3 \ + getcap.3 cgetnum.3 \ + getcap.3 cgetset.3 \ + getcap.3 cgetstr.3 \ + getcap.3 cgetustr.3 +MLINKS+=getcwd.3 getwd.3 +MLINKS+=getcontext.3 getcontextx.3 +MLINKS+=getcontext.3 setcontext.3 +MLINKS+=getdomainname.3 setdomainname.3 +MLINKS+=getfsent.3 endfsent.3 \ + getfsent.3 getfsfile.3 \ + getfsent.3 getfsspec.3 \ + getfsent.3 getfstype.3 \ + getfsent.3 setfsent.3 \ + getfsent.3 setfstab.3 \ + getfsent.3 getfstab.3 +MLINKS+=getgrent.3 endgrent.3 \ + getgrent.3 getgrgid.3 \ + getgrent.3 getgrnam.3 \ + getgrent.3 setgrent.3 \ + getgrent.3 setgroupent.3 \ + getgrent.3 getgrent_r.3 \ + getgrent.3 getgrnam_r.3 \ + getgrent.3 getgrgid_r.3 +MLINKS+=gethostname.3 sethostname.3 +MLINKS+=getnetgrent.3 endnetgrent.3 \ + getnetgrent.3 getnetgrent_r.3 \ + getnetgrent.3 innetgr.3 \ + getnetgrent.3 setnetgrent.3 +MLINKS+=getprogname.3 setprogname.3 +MLINKS+=getpwent.3 endpwent.3 \ + getpwent.3 getpwnam.3 \ + getpwent.3 getpwuid.3 \ + getpwent.3 setpassent.3 \ + getpwent.3 setpwent.3 \ + getpwent.3 setpwfile.3 \ + getpwent.3 getpwent_r.3 \ + getpwent.3 getpwnam_r.3 \ + getpwent.3 getpwuid_r.3 +MLINKS+=getttyent.3 endttyent.3 \ + getttyent.3 getttynam.3 \ + getttyent.3 isdialuptty.3 \ + getttyent.3 isnettty.3 \ + getttyent.3 setttyent.3 +MLINKS+=getusershell.3 endusershell.3 \ + getusershell.3 setusershell.3 +MLINKS+=getutxent.3 endutxent.3 \ + getutxent.3 getutxid.3 \ + getutxent.3 getutxline.3 \ + getutxent.3 getutxuser.3 \ + getutxent.3 pututxline.3 \ + getutxent.3 setutxdb.3 \ + getutxent.3 setutxent.3 \ + getutxent.3 utmpx.3 +MLINKS+=glob.3 globfree.3 +MLINKS+=isgreater.3 isgreaterequal.3 \ + isgreater.3 isless.3 \ + isgreater.3 islessequal.3 \ + isgreater.3 islessgreater.3 \ + isgreater.3 isunordered.3 +MLINKS+=ldexp.3 ldexpf.3 \ + ldexp.3 ldexpl.3 +MLINKS+=makecontext.3 swapcontext.3 +MLINKS+=modf.3 modff.3 \ + modf.3 modfl.3 +MLINKS+=popen.3 pclose.3 +MLINKS+=posix_spawn.3 posix_spawnp.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addclose.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addclosefrom_np.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_adddup2.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addchdir_np.3 \ + posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_addfchdir_np.3 \ + posix_spawn_file_actions_init.3 posix_spawn_file_actions_destroy.3 \ + posix_spawnattr_getflags.3 posix_spawnattr_setflags.3 \ + posix_spawnattr_getpgroup.3 posix_spawnattr_setpgroup.3 \ + posix_spawnattr_getschedparam.3 posix_spawnattr_setschedparam.3 \ + posix_spawnattr_getschedpolicy.3 posix_spawnattr_setschedpolicy.3 \ + posix_spawnattr_getsigdefault.3 posix_spawnattr_setsigdefault.3 \ + posix_spawnattr_getsigmask.3 posix_spawnattr_setsigmask.3 \ + posix_spawnattr_init.3 posix_spawnattr_destroy.3 +MLINKS+=psignal.3 psiginfo.3 \ + psignal.3 sig2str.3 \ + psignal.3 str2sig.3 \ + psignal.3 strsignal.3 \ + psignal.3 sys_siglist.3 \ + psignal.3 sys_signame.3 +MLINKS+=pwcache.3 gid_from_group.3 \ + pwcache.3 group_from_gid.3 \ + pwcache.3 pwcache_groupdb.3 \ + pwcache.3 pwcache_userdb.3 \ + pwcache.3 uid_from_user.3 \ + pwcache.3 user_from_uid.3 +MLINKS+=rand48.3 _rand48.3 \ + rand48.3 drand48.3 \ + rand48.3 erand48.3 \ + rand48.3 jrand48.3 \ + rand48.3 lcong48.3 \ + rand48.3 lrand48.3 \ + rand48.3 mrand48.3 \ + rand48.3 nrand48.3 \ + rand48.3 seed48.3 \ + rand48.3 srand48.3 +MLINKS+=rtld_get_var.3 \ + rtld_set_var.3 +MLINKS+=scandir.3 alphasort.3 \ + scandir.3 fdscandir.3 \ + scandir.3 fdscandir_b.3 \ + scandir.3 scandir_b.3 \ + scandir.3 scandirat.3 \ + scandir.3 scandirat_b.3 \ + scandir.3 versionsort.3 +MLINKS+=sem_open.3 sem_close.3 \ + sem_open.3 sem_unlink.3 +MLINKS+=sem_wait.3 sem_trywait.3 +MLINKS+=sem_timedwait.3 sem_clockwait_np.3 +MLINKS+=setjmp.3 _longjmp.3 \ + setjmp.3 _setjmp.3 \ + setjmp.3 longjmp.3 \ + setjmp.3 longjmperr.3 \ + setjmp.3 longjmperror.3 \ + setjmp.3 siglongjmp.3 \ + setjmp.3 sigsetjmp.3 +MLINKS+=setmode.3 getmode.3 +MLINKS+=setproctitle.3 setproctitle_fast.3 +MLINKS+=sigsetops.3 sigaddset.3 \ + sigsetops.3 sigandset.3 \ + sigsetops.3 sigdelset.3 \ + sigsetops.3 sigemptyset.3 \ + sigsetops.3 sigfillset.3 \ + sigsetops.3 sigisemptyset.3 \ + sigsetops.3 sigismember.3 \ + sigsetops.3 sigorset.3 +MLINKS+=statvfs.3 fstatvfs.3 +MLINKS+=stringlist.3 sl_add.3 \ + stringlist.3 sl_find.3 \ + stringlist.3 sl_free.3 \ + stringlist.3 sl_init.3 +MLINKS+=strtofflags.3 fflagstostr.3 +MLINKS+=sysctl.3 sysctlbyname.3 \ + sysctl.3 sysctlnametomib.3 +MLINKS+=syslog.3 closelog.3 \ + syslog.3 openlog.3 \ + syslog.3 setlogmask.3 \ + syslog.3 vsyslog.3 +MLINKS+=tcgetwinsize.3 tcsetwinsize.3 +MLINKS+=tcsendbreak.3 tcdrain.3 \ + tcsendbreak.3 tcflow.3 \ + tcsendbreak.3 tcflush.3 +MLINKS+=tcsetattr.3 cfgetispeed.3 \ + tcsetattr.3 cfgetospeed.3 \ + tcsetattr.3 cfmakeraw.3 \ + tcsetattr.3 cfmakesane.3 \ + tcsetattr.3 cfsetispeed.3 \ + tcsetattr.3 cfsetospeed.3 \ + tcsetattr.3 cfsetspeed.3 \ + tcsetattr.3 tcgetattr.3 +MLINKS+=ttyname.3 isatty.3 \ + ttyname.3 ttyname_r.3 +MLINKS+=unvis.3 strunvis.3 \ + unvis.3 strunvisx.3 +MLINKS+=vis.3 nvis.3 \ + vis.3 snvis.3 \ + vis.3 strenvisx.3 \ + vis.3 strnunvis.3 \ + vis.3 strnunvisx.3 \ + vis.3 strnvis.3 \ + vis.3 strnvisx.3 \ + vis.3 strsenvisx.3 \ + vis.3 strsnvis.3 \ + vis.3 strsnvisx.3 \ + vis.3 strsvis.3 \ + vis.3 strsvisx.3 \ + vis.3 strvis.3 \ + vis.3 strvisx.3 \ + vis.3 svis.3 + +MLINKS+=wordexp.3 wordfree.3 + +.include <src.tools.mk> + +afterinstallconfig: install-passwd +install-passwd: .PHONY +.if ${MK_TCSH} == "no" + sed -i "" -e 's;/bin/csh;/bin/sh;' ${DESTDIR}/etc/master.passwd +.endif + ${PWD_MKDB_CMD} -i -p -d ${DESTDIR}/etc ${DESTDIR}/etc/master.passwd +.if defined(NO_ROOT) && defined(METALOG) + ( \ + echo ".${DISTBASE}/etc/pwd.db type=file mode=0644 uname=root gname=wheel"; \ + echo ".${DISTBASE}/etc/spwd.db type=file mode=0600 uname=root gname=wheel"; \ + echo ".${DISTBASE}/etc/passwd type=file mode=0644 uname=root gname=wheel"; \ + ) | cat -l >> ${METALOG} +.endif diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map new file mode 100644 index 000000000000..494b65bc5cc1 --- /dev/null +++ b/lib/libc/gen/Symbol.map @@ -0,0 +1,605 @@ +FBSD_1.0 { + __xuname; + pthread_atfork; + pthread_attr_destroy; + pthread_attr_get_np; + pthread_attr_getdetachstate; + pthread_attr_getguardsize; + pthread_attr_getinheritsched; + pthread_attr_getschedparam; + pthread_attr_getschedpolicy; + pthread_attr_getscope; + pthread_attr_getstackaddr; + pthread_attr_getstacksize; + pthread_attr_init; + pthread_attr_setdetachstate; + pthread_attr_setguardsize; + pthread_attr_setinheritsched; + pthread_attr_setschedparam; + pthread_attr_setschedpolicy; + pthread_attr_setscope; + pthread_attr_setstackaddr; + pthread_attr_setstacksize; + pthread_cancel; + pthread_cleanup_pop; + pthread_cleanup_push; + pthread_cond_broadcast; + pthread_cond_destroy; + pthread_cond_init; + pthread_cond_signal; + pthread_cond_timedwait; + pthread_cond_wait; + pthread_detach; + pthread_equal; + pthread_exit; + pthread_getspecific; + pthread_join; + pthread_key_create; + pthread_key_delete; + pthread_kill; + pthread_main_np; + pthread_mutex_destroy; + pthread_mutex_init; + pthread_mutex_lock; + pthread_mutex_trylock; + pthread_mutex_unlock; + pthread_mutexattr_destroy; + pthread_mutexattr_init; + pthread_mutexattr_settype; + pthread_once; + pthread_resume_all_np; + pthread_rwlock_destroy; + pthread_rwlock_init; + pthread_rwlock_rdlock; + pthread_rwlock_tryrdlock; + pthread_rwlock_trywrlock; + pthread_rwlock_unlock; + pthread_rwlock_wrlock; + pthread_self; + pthread_setcancelstate; + pthread_setcanceltype; + pthread_setspecific; + pthread_sigmask; + pthread_suspend_all_np; + pthread_testcancel; + alarm; + arc4random; + __assert; + check_utility_compat; + clock; + closedir; + confstr; + ctermid; + ctermid_r; + daemon; + getdiskbyname; + dladdr; + dlclose; + dlerror; + dlfunc; + dllockinit; + dlopen; + dlsym; + dlvsym; + dlinfo; + dl_iterate_phdr; + drand48; + erand48; + err_set_file; + err_set_exit; + err; + verr; + errc; + verrc; + errx; + verrx; + warn; + vwarn; + warnc; + vwarnc; + warnx; + vwarnx; + sys_errlist; + sys_nerr; + exect; + execl; + execle; + execlp; + execv; + execvp; + execvP; + fabs; + fmtcheck; + fmtmsg; + fnmatch; + __fpclassifyf; + __fpclassifyd; + __fpclassifyl; + frexp; + setfstab; + getfstab; + getfsent; + getfsspec; + getfsfile; + setfsent; + endfsent; + ftok; + getbootfile; + getbsize; + cgetset; + cgetcap; + cgetent; + cgetmatch; + cgetfirst; + cgetclose; + cgetnext; + cgetstr; + cgetustr; + cgetnum; + getcwd; + getdomainname; + setgrent; + setgroupent; + endgrent; + getgrent_r; + getgrnam_r; + getgrgid_r; + getgrnam; + getgrgid; + getgrent; + /* + * Why are __gr_parse_entry() and __gr_match_entry() not static in + * gen/getgrent.c? + */ + getgrouplist; + gethostname; + getloadavg; + getlogin; + setnetgrent; + getnetgrent; + endnetgrent; + innetgr; + getosreldate; + getpeereid; + _getprogname; + getprogname; + setpwent; + setpassent; + endpwent; + getpwent_r; + getpwnam_r; + getpwuid_r; + getpwnam; + getpwuid; + getpwent; + getttynam; + getttyent; + setttyent; + endttyent; + isdialuptty; + isnettty; + getusershell; + endusershell; + setusershell; + getvfsbyname; + __nan; + __isnan; + isnan; + __isnanf; + isnanf; + __infinity; + __isinf; + isinf; + __isinff; + __isinfl; + isatty; + jrand48; + lcong48; + ldexp; + lockf; + lrand48; + makecontext; + modf; + mrand48; + nice; + nlist; + nrand48; + opendir; + pause; + posix_madvise; + popen; + pclose; + psignal; + raise; + readpassphrase; + getpass; + rewinddir; + seed48; + seekdir; + user_from_uid; + group_from_gid; + setdomainname; + sethostname; + _setjmp; + _longjmp; + setjmp; + longjmp; + sigsetjmp; + siglongjmp; + longjmperror; + getmode; + setmode; + setproctitle; + setprogname; + siginterrupt; + sys_signame; + sys_siglist; + sys_nsig; + signal; + sigaddset; + sigdelset; + sigemptyset; + sigfillset; + sigismember; + sleep; + srand48; + fstatvfs; + statvfs; + sl_init; + sl_add; + sl_free; + sl_find; + fflagstostr; + strtofflags; + sysconf; + sysctl; + sysctlbyname; + sysctlnametomib; + syslog; + vsyslog; + openlog; + closelog; + setlogmask; + ttyname_r; + ttyname; + times; + time; + telldir; + tcgetattr; + tcsetattr; + tcsetpgrp; + tcgetpgrp; + cfgetospeed; + cfgetispeed; + cfsetospeed; + cfsetispeed; + cfsetspeed; + cfmakeraw; + tcsendbreak; + _init_tls; + __tls_get_addr; + tcdrain; + tcflush; + tcflow; + ualarm; + ulimit; + uname; + strunvis; + strunvisx; + usleep; + utime; + valloc; + vis; + strvis; + strvisx; + wait; + wait3; + waitpid; + wordexp; + wordfree; +}; + +FBSD_1.1 { + arc4random_buf; + arc4random_uniform; + fdevname; + fdevname_r; + fdopendir; + feature_present; + posix_spawn; + posix_spawn_file_actions_addclose; + posix_spawn_file_actions_adddup2; + posix_spawn_file_actions_addopen; + posix_spawn_file_actions_destroy; + posix_spawn_file_actions_init; + posix_spawnattr_destroy; + posix_spawnattr_getflags; + posix_spawnattr_getpgroup; + posix_spawnattr_getschedparam; + posix_spawnattr_getschedpolicy; + posix_spawnattr_getsigdefault; + posix_spawnattr_getsigmask; + posix_spawnattr_init; + posix_spawnattr_setflags; + posix_spawnattr_setpgroup; + posix_spawnattr_setschedparam; + posix_spawnattr_setschedpolicy; + posix_spawnattr_setsigdefault; + posix_spawnattr_setsigmask; + posix_spawnp; + semctl; + tcgetsid; + tcsetsid; + __pthread_cleanup_pop_imp; + __pthread_cleanup_push_imp; +}; + +FBSD_1.2 { + cfmakesane; + endutxent; + getutxent; + getutxid; + getutxline; + getutxuser; + pthread_getthreadid_np; + pututxline; + sem_close; + sem_destroy; + sem_getvalue; + sem_init; + sem_open; + sem_post; + sem_timedwait; + sem_trywait; + sem_unlink; + sem_wait; + setutxdb; + setutxent; +}; + +FBSD_1.3 { + cap_sandboxed; + clock_getcpuclockid; + dirfd; + dup3; + fdclosedir; + fdlopen; + __FreeBSD_libc_enter_restricted_mode; + getcontextx; + gid_from_group; + nvis; + pwcache_userdb; + pwcache_groupdb; + snvis; + strenvisx; + strnunvis; + strnunvisx; + strnvis; + strnvisx; + strsenvisx; + strsnvis; + strsnvisx; + strsvis; + strsvisx; + svis; + uid_from_user; + unvis; + waitid; +}; + +FBSD_1.4 { + getnetgrent_r; + pthread_mutex_consistent; + pthread_mutexattr_getrobust; + pthread_mutexattr_setrobust; + stravis; +}; + +FBSD_1.5 { + alphasort; + basename; + daemonfd; + devname; + devname_r; + dirname; + fts_children; + fts_close; + fts_get_clientptr; + fts_get_stream; + fts_open; + fts_read; + fts_set; + fts_set_clientptr; + ftw; + getentropy; + getmntinfo; + glob; + globfree; + nftw; + readdir; + readdir_r; + scandir; + sem_clockwait_np; + setproctitle_fast; + timespec_get; +}; + +FBSD_1.6 { + eventfd; + eventfd_read; + eventfd_write; + getlogin_r; + memalign; + memfd_create; + pthread_getname_np; + scandir_b; + sigandset; + sigisemptyset; + sigorset; + tcgetwinsize; + tcsetwinsize; +}; + +FBSD_1.7 { + kqueue1; + posix_spawn_file_actions_addchdir_np; + posix_spawn_file_actions_addclosefrom_np; + posix_spawn_file_actions_addfchdir_np; + scandirat; + sched_getaffinity; + sched_setaffinity; + versionsort; + __cpuset_alloc; + __cpuset_free; +}; + +FBSD_1.8 { + aio_read2; + aio_write2; + execvpe; + fdscandir; + fdscandir_b; + fts_open_b; + glob_b; + initgroups; + inotify_add_watch; + inotify_init; + inotify_init1; + psiginfo; + rtld_get_var; + rtld_set_var; + scandirat_b; + uexterr_gettext; + sig2str; + str2sig; +}; + +FBSDprivate_1.0 { + /* needed by thread libraries */ + __thr_jtable; + + _dl_iterate_phdr_locked; + _pthread_atfork; + _pthread_attr_destroy; + _pthread_attr_getdetachstate; + _pthread_attr_getguardsize; + _pthread_attr_getinheritsched; + _pthread_attr_getschedparam; + _pthread_attr_getschedpolicy; + _pthread_attr_getscope; + _pthread_attr_getstackaddr; + _pthread_attr_getstacksize; + _pthread_attr_init; + _pthread_attr_setdetachstate; + _pthread_attr_setguardsize; + _pthread_attr_setinheritsched; + _pthread_attr_setschedparam; + _pthread_attr_setschedpolicy; + _pthread_attr_setscope; + _pthread_attr_setstackaddr; + _pthread_attr_setstacksize; + _pthread_cancel; + _pthread_cancel_enter; + _pthread_cancel_leave; + _pthread_cleanup_pop; + _pthread_cleanup_push; + _pthread_cond_broadcast; + _pthread_cond_destroy; + _pthread_cond_init; + _pthread_cond_signal; + _pthread_cond_timedwait; + _pthread_cond_wait; + _pthread_detach; + _pthread_equal; + _pthread_exit; + _pthread_getspecific; + _pthread_join; + _pthread_key_create; + _pthread_key_delete; + _pthread_kill; + _pthread_main_np; + _pthread_mutex_destroy; + _pthread_mutex_init_calloc_cb; + _pthread_mutex_init; + _pthread_mutex_lock; + _pthread_mutex_trylock; + _pthread_mutex_unlock; + _pthread_mutexattr_destroy; + _pthread_mutexattr_init; + _pthread_mutexattr_settype; + _pthread_once; + _pthread_rwlock_destroy; + _pthread_rwlock_init; + _pthread_rwlock_rdlock; + _pthread_rwlock_tryrdlock; + _pthread_rwlock_trywrlock; + _pthread_rwlock_unlock; + _pthread_rwlock_wrlock; + _pthread_self; + _pthread_setcancelstate; + _pthread_setcanceltype; + _pthread_setspecific; + _pthread_sigmask; + _pthread_testcancel; + _spinlock; + _spinunlock; + _rtld_addr_phdr; + _rtld_atfork_pre; + _rtld_atfork_post; + _rtld_error; /* for private use */ + _rtld_get_stack_prot; + _rtld_is_dlopened; + _rtld_thread_init; /* for private use */ + __elf_phdr_match_addr; + _err; + _warn; + __fmtcheck; + /* __pw_match_entry; */ + /* __pw_parse_entry; */ + __fdnlist; /* used by libkvm */ + /* __elf_is_okay__; */ + /* __elf_fdnlist; */ + __opendir2; + __pause; + _pause; + __raise; + _raise; + __sleep; + _sleep; + _rtld_allocate_tls; + _rtld_free_tls; +#if defined(i386) + ___libc_tls_get_addr; /* x86 only */ +#endif + __libc_tls_get_addr; + __tcdrain; + _tcdrain; + __usleep; + _usleep; + __wait; + _wait; + __waitpid; + _waitpid; + + __libc_interposing_slot; + + _libc_sem_init_compat; + _libc_sem_destroy_compat; + _libc_sem_open_compat; + _libc_sem_close_compat; + _libc_sem_unlink_compat; + _libc_sem_wait_compat; + _libc_sem_trywait_compat; + _libc_sem_timedwait_compat; + _libc_sem_post_compat; + _libc_sem_getvalue_compat; + + __libc_tcdrain; + + __pthread_map_stacks_exec; + __fillcontextx; + __fillcontextx2; + __getcontextx_size; + __makecontext; + __uexterr_format; +}; diff --git a/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c b/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c new file mode 100644 index 000000000000..3a81ace8a0f4 --- /dev/null +++ b/lib/libc/gen/__pthread_mutex_init_calloc_cb_stub.c @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2014 The FreeBSD Foundation. + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <pthread.h> +#include "libc_private.h" + +int +_pthread_mutex_init_calloc_cb_stub(pthread_mutex_t *mutex, + void *(calloc_cb)(size_t, size_t)) +{ + + return (0); +} diff --git a/lib/libc/gen/__xuname.c b/lib/libc/gen/__xuname.c new file mode 100644 index 000000000000..4257c42f9519 --- /dev/null +++ b/lib/libc/gen/__xuname.c @@ -0,0 +1,142 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/utsname.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +int +__xuname(int namesize, void *namebuf) +{ + int mib[2], rval; + size_t len; + char *p, *q; + int oerrno; + + rval = 0; + q = (char *)namebuf; + + mib[0] = CTL_KERN; + + if ((p = getenv("UNAME_s"))) + strlcpy(q, p, namesize); + else { + mib[1] = KERN_OSTYPE; + len = namesize; + oerrno = errno; + if (sysctl(mib, 2, q, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + q[namesize - 1] = '\0'; + } + q += namesize; + + mib[1] = KERN_HOSTNAME; + len = namesize; + oerrno = errno; + if (sysctl(mib, 2, q, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + q[namesize - 1] = '\0'; + q += namesize; + + if ((p = getenv("UNAME_r"))) + strlcpy(q, p, namesize); + else { + mib[1] = KERN_OSRELEASE; + len = namesize; + oerrno = errno; + if (sysctl(mib, 2, q, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + q[namesize - 1] = '\0'; + } + q += namesize; + + if ((p = getenv("UNAME_v"))) + strlcpy(q, p, namesize); + else { + + /* + * The version may have newlines in it, turn them into + * spaces. + */ + mib[1] = KERN_VERSION; + len = namesize; + oerrno = errno; + if (sysctl(mib, 2, q, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + q[namesize - 1] = '\0'; + for (p = q; len--; ++p) { + if (*p == '\n' || *p == '\t') { + if (len > 1) + *p = ' '; + else + *p = '\0'; + } + } + } + q += namesize; + + if ((p = getenv("UNAME_m"))) + strlcpy(q, p, namesize); + else { + mib[0] = CTL_HW; + mib[1] = HW_MACHINE; + len = namesize; + oerrno = errno; + if (sysctl(mib, 2, q, &len, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = oerrno; + else + rval = -1; + } + q[namesize - 1] = '\0'; + } + + return (rval); +} diff --git a/lib/libc/gen/_once_stub.c b/lib/libc/gen/_once_stub.c new file mode 100644 index 000000000000..518072cbd28f --- /dev/null +++ b/lib/libc/gen/_once_stub.c @@ -0,0 +1,63 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2009 Hudson River Trading LLC + * Written by: John H. Baldwin <jhb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <pthread.h> +#include "un-namespace.h" +#include "libc_private.h" + +/* This implements pthread_once() for the single-threaded case. */ +static int +_libc_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + + if (once_control->state == PTHREAD_DONE_INIT) + return (0); + init_routine(); + once_control->state = PTHREAD_DONE_INIT; + return (0); +} + +/* + * This is the internal interface provided to libc. It will use + * pthread_once() from the threading library in a multi-threaded + * process and _libc_once() for a single-threaded library. Because + * _libc_once() uses the same ABI for the values in the pthread_once_t + * structure as the threading library, it is safe for a process to + * switch from _libc_once() to pthread_once() when threading is + * enabled. + */ +int +_once(pthread_once_t *once_control, void (*init_routine)(void)) +{ + + if (__isthreaded) + return (_pthread_once(once_control, init_routine)); + return (_libc_once(once_control, init_routine)); +} diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c new file mode 100644 index 000000000000..d867ee4db51e --- /dev/null +++ b/lib/libc/gen/_pthread_stubs.c @@ -0,0 +1,363 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <signal.h> +#include <pthread.h> +#include <stdlib.h> +#include <errno.h> + +#include "libc_private.h" + +/* + * Weak symbols: All libc internal usage of these functions should + * use the weak symbol versions (_pthread_XXX). If libpthread is + * linked, it will override these functions with (non-weak) routines. + * The _pthread_XXX functions are provided solely for internal libc + * usage to avoid unwanted cancellation points and to differentiate + * between application locks and libc locks (threads holding the + * latter can't be allowed to exit/terminate). + */ + +/* Define a null pthread structure just to satisfy _pthread_self. */ +struct pthread { +}; + +static struct pthread main_thread; + +static int stub_main(void); +static void stub_void(void); +static void *stub_null(void); +static struct pthread *stub_self(void); +static int stub_zero(void); +static int stub_fail(void); +static int stub_true(void); +static void stub_exit(void); +static int stub_esrch(void); +static int stub_getname_np(pthread_t, char *, size_t); + +#define PJT_DUAL_ENTRY(entry) \ + (pthread_func_t)entry, (pthread_func_t)entry + +__attribute__((visibility("protected"))) +pthread_func_entry_t __thr_jtable[PJT_MAX] = { + [PJT_ATFORK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETDETACHSTATE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETGUARDSIZE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETINHERITSCHED] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETSCHEDPARAM] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETSCHEDPOLICY] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETSCOPE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETSTACKADDR] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GETSTACKSIZE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_INIT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETDETACHSTATE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETGUARDSIZE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETINHERITSCHED] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETSCHEDPARAM] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETSCHEDPOLICY] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETSCOPE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETSTACKADDR] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_SETSTACKSIZE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_CANCEL] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_CLEANUP_POP] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_CLEANUP_PUSH] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_COND_BROADCAST] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_COND_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_COND_INIT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_COND_SIGNAL] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_COND_TIMEDWAIT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_COND_WAIT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_DETACH] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_EQUAL] = {PJT_DUAL_ENTRY(stub_true)}, + [PJT_EXIT] = {PJT_DUAL_ENTRY(stub_exit)}, + [PJT_GETSPECIFIC] = {PJT_DUAL_ENTRY(stub_null)}, + [PJT_JOIN] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_KEY_CREATE] = {PJT_DUAL_ENTRY(stub_fail)}, + [PJT_KEY_DELETE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_KILL] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MAIN_NP] = {PJT_DUAL_ENTRY(stub_main)}, + [PJT_MUTEXATTR_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEXATTR_INIT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEXATTR_SETTYPE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEX_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEX_INIT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEX_LOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEX_TRYLOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEX_UNLOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ONCE] = {PJT_DUAL_ENTRY(stub_fail)}, + [PJT_RWLOCK_DESTROY] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_RWLOCK_INIT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_RWLOCK_RDLOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_RWLOCK_TRYRDLOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_RWLOCK_TRYWRLOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_RWLOCK_UNLOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_RWLOCK_WRLOCK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_SELF] = {PJT_DUAL_ENTRY(stub_self)}, + [PJT_SETCANCELSTATE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_SETCANCELTYPE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_SETSPECIFIC] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_SIGMASK] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_TESTCANCEL] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_CLEANUP_POP_IMP] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_CLEANUP_PUSH_IMP] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_CANCEL_ENTER] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_CANCEL_LEAVE] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEX_CONSISTENT] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEXATTR_GETROBUST] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_MUTEXATTR_SETROBUST] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_GETTHREADID_NP] = {PJT_DUAL_ENTRY(stub_zero)}, + [PJT_ATTR_GET_NP] = {PJT_DUAL_ENTRY(stub_esrch)}, + [PJT_GETNAME_NP] = {PJT_DUAL_ENTRY(stub_getname_np)}, + [PJT_SUSPEND_ALL_NP] = {PJT_DUAL_ENTRY(stub_void)}, + [PJT_RESUME_ALL_NP] = {PJT_DUAL_ENTRY(stub_void)}, +}; + +/* + * Weak aliases for exported (pthread_*) and internal (_pthread_*) routines. + */ +#define WEAK_REF(sym, alias) __weak_reference(sym, alias) + +#define FUNC_TYPE(name) __CONCAT(name, _func_t) +#define FUNC_INT(name) __CONCAT(name, _int) +#define FUNC_EXP(name) __CONCAT(name, _exp) + +#define STUB_FUNC(name, idx, ret) \ + static ret FUNC_EXP(name)(void) __used; \ + static ret FUNC_INT(name)(void) __used; \ + WEAK_REF(FUNC_EXP(name), name); \ + WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \ + typedef ret (*FUNC_TYPE(name))(void); \ + static ret FUNC_EXP(name)(void) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \ + return (func()); \ + } \ + static ret FUNC_INT(name)(void) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \ + return (func()); \ + } + +#define STUB_FUNC1(name, idx, ret, p0_type) \ + static ret FUNC_EXP(name)(p0_type) __used; \ + static ret FUNC_INT(name)(p0_type) __used; \ + WEAK_REF(FUNC_EXP(name), name); \ + WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \ + typedef ret (*FUNC_TYPE(name))(p0_type); \ + static ret FUNC_EXP(name)(p0_type p0) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \ + return (func(p0)); \ + } \ + static ret FUNC_INT(name)(p0_type p0) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \ + return (func(p0)); \ + } + +#define STUB_FUNC2(name, idx, ret, p0_type, p1_type) \ + static ret FUNC_EXP(name)(p0_type, p1_type) __used; \ + static ret FUNC_INT(name)(p0_type, p1_type) __used; \ + WEAK_REF(FUNC_EXP(name), name); \ + WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \ + typedef ret (*FUNC_TYPE(name))(p0_type, p1_type); \ + static ret FUNC_EXP(name)(p0_type p0, p1_type p1) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \ + return (func(p0, p1)); \ + } \ + static ret FUNC_INT(name)(p0_type p0, p1_type p1) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \ + return (func(p0, p1)); \ + } + +#define STUB_FUNC3(name, idx, ret, p0_type, p1_type, p2_type) \ + static ret FUNC_EXP(name)(p0_type, p1_type, p2_type) __used; \ + static ret FUNC_INT(name)(p0_type, p1_type, p2_type) __used; \ + WEAK_REF(FUNC_EXP(name), name); \ + WEAK_REF(FUNC_INT(name), __CONCAT(_, name)); \ + typedef ret (*FUNC_TYPE(name))(p0_type, p1_type, p2_type); \ + static ret FUNC_EXP(name)(p0_type p0, p1_type p1, p2_type p2) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][0]; \ + return (func(p0, p1, p2)); \ + } \ + static ret FUNC_INT(name)(p0_type p0, p1_type p1, p2_type p2) \ + { \ + FUNC_TYPE(name) func; \ + func = (FUNC_TYPE(name))__thr_jtable[idx][1]; \ + return (func(p0, p1, p2)); \ + } + +STUB_FUNC1(pthread_cond_broadcast, PJT_COND_BROADCAST, int, void *) +STUB_FUNC1(pthread_cond_destroy, PJT_COND_DESTROY, int, void *) +STUB_FUNC2(pthread_cond_init, PJT_COND_INIT, int, void *, void *) +STUB_FUNC1(pthread_cond_signal, PJT_COND_SIGNAL, int, void *) +STUB_FUNC2(pthread_cond_wait, PJT_COND_WAIT, int, void *, void *) +STUB_FUNC1(pthread_getspecific, PJT_GETSPECIFIC, void *, pthread_key_t) +STUB_FUNC2(pthread_key_create, PJT_KEY_CREATE, int, void *, void *) +STUB_FUNC1(pthread_key_delete, PJT_KEY_DELETE, int, pthread_key_t) +STUB_FUNC(pthread_main_np, PJT_MAIN_NP, int) +STUB_FUNC1(pthread_mutex_destroy, PJT_MUTEX_DESTROY, int, void *) +STUB_FUNC2(pthread_mutex_init, PJT_MUTEX_INIT, int, void *, void *) +STUB_FUNC1(pthread_mutex_lock, PJT_MUTEX_LOCK, int, void *) +STUB_FUNC1(pthread_mutex_trylock, PJT_MUTEX_TRYLOCK, int, void *) +STUB_FUNC1(pthread_mutex_unlock, PJT_MUTEX_UNLOCK, int, void *) +STUB_FUNC1(pthread_mutex_consistent, PJT_MUTEX_CONSISTENT, int, void *) +STUB_FUNC1(pthread_mutexattr_destroy, PJT_MUTEXATTR_DESTROY, int, void *) +STUB_FUNC1(pthread_mutexattr_init, PJT_MUTEXATTR_INIT, int, void *) +STUB_FUNC2(pthread_mutexattr_settype, PJT_MUTEXATTR_SETTYPE, int, void *, int) +STUB_FUNC2(pthread_mutexattr_getrobust, PJT_MUTEXATTR_GETROBUST, int, void *, + int *) +STUB_FUNC2(pthread_mutexattr_setrobust, PJT_MUTEXATTR_SETROBUST, int, void *, + int) +STUB_FUNC2(pthread_once, PJT_ONCE, int, void *, void *) +STUB_FUNC1(pthread_rwlock_destroy, PJT_RWLOCK_DESTROY, int, void *) +STUB_FUNC2(pthread_rwlock_init, PJT_RWLOCK_INIT, int, void *, void *) +STUB_FUNC1(pthread_rwlock_rdlock, PJT_RWLOCK_RDLOCK, int, void *) +STUB_FUNC1(pthread_rwlock_tryrdlock, PJT_RWLOCK_TRYRDLOCK, int, void *) +STUB_FUNC1(pthread_rwlock_trywrlock, PJT_RWLOCK_TRYWRLOCK, int, void *) +STUB_FUNC1(pthread_rwlock_unlock, PJT_RWLOCK_UNLOCK, int, void *) +STUB_FUNC1(pthread_rwlock_wrlock, PJT_RWLOCK_WRLOCK, int, void *) +STUB_FUNC(pthread_self, PJT_SELF, pthread_t) +STUB_FUNC(pthread_getthreadid_np, PJT_GETTHREADID_NP, int) +STUB_FUNC2(pthread_setspecific, PJT_SETSPECIFIC, int, pthread_key_t, void *) +STUB_FUNC3(pthread_sigmask, PJT_SIGMASK, int, int, void *, void *) +STUB_FUNC3(pthread_atfork, PJT_ATFORK, int, void *, void *, void*) +STUB_FUNC1(pthread_attr_destroy, PJT_ATTR_DESTROY, int, void *); +STUB_FUNC2(pthread_attr_getdetachstate, PJT_ATTR_GETDETACHSTATE, int, void *, void *) +STUB_FUNC2(pthread_attr_getguardsize, PJT_ATTR_GETGUARDSIZE, int, void *, void *) +STUB_FUNC2(pthread_attr_getstackaddr, PJT_ATTR_GETSTACKADDR, int, void *, void *) +STUB_FUNC2(pthread_attr_getstacksize, PJT_ATTR_GETSTACKSIZE, int, void *, void *) +STUB_FUNC2(pthread_attr_getinheritsched, PJT_ATTR_GETINHERITSCHED, int, void *, void *) +STUB_FUNC2(pthread_attr_getschedparam, PJT_ATTR_GETSCHEDPARAM, int, void *, void *) +STUB_FUNC2(pthread_attr_getschedpolicy, PJT_ATTR_GETSCHEDPOLICY, int, void *, void *) +STUB_FUNC2(pthread_attr_getscope, PJT_ATTR_GETSCOPE, int, void *, void *) +STUB_FUNC1(pthread_attr_init, PJT_ATTR_INIT, int, void *) +STUB_FUNC2(pthread_attr_setdetachstate, PJT_ATTR_SETDETACHSTATE, int, void *, int) +STUB_FUNC2(pthread_attr_setguardsize, PJT_ATTR_SETGUARDSIZE, int, void *, size_t) +STUB_FUNC2(pthread_attr_setstackaddr, PJT_ATTR_SETSTACKADDR, int, void *, void *) +STUB_FUNC2(pthread_attr_setstacksize, PJT_ATTR_SETSTACKSIZE, int, void *, size_t) +STUB_FUNC2(pthread_attr_setinheritsched, PJT_ATTR_SETINHERITSCHED, int, void *, int) +STUB_FUNC2(pthread_attr_setschedparam, PJT_ATTR_SETSCHEDPARAM, int, void *, void *) +STUB_FUNC2(pthread_attr_setschedpolicy, PJT_ATTR_SETSCHEDPOLICY, int, void *, int) +STUB_FUNC2(pthread_attr_setscope, PJT_ATTR_SETSCOPE, int, void *, int) +STUB_FUNC1(pthread_cancel, PJT_CANCEL, int, void *) +STUB_FUNC1(pthread_cleanup_pop, PJT_CLEANUP_POP, int, int) +STUB_FUNC2(pthread_cleanup_push, PJT_CLEANUP_PUSH, void, void *, void *) +STUB_FUNC3(pthread_cond_timedwait, PJT_COND_TIMEDWAIT, int, void *, void *, void *) +STUB_FUNC1(pthread_detach, PJT_DETACH, int, void *) +STUB_FUNC2(pthread_equal, PJT_EQUAL, int, void *, void *) +STUB_FUNC1(pthread_exit, PJT_EXIT, void, void *) +STUB_FUNC2(pthread_join, PJT_JOIN, int, void *, void *) +STUB_FUNC2(pthread_kill, PJT_KILL, int, void *, int) +STUB_FUNC2(pthread_setcancelstate, PJT_SETCANCELSTATE, int, int, void *) +STUB_FUNC2(pthread_setcanceltype, PJT_SETCANCELTYPE, int, int, void *) +STUB_FUNC(pthread_testcancel, PJT_TESTCANCEL, void) +STUB_FUNC1(__pthread_cleanup_pop_imp, PJT_CLEANUP_POP_IMP, void, int) +STUB_FUNC3(__pthread_cleanup_push_imp, PJT_CLEANUP_PUSH_IMP, void, void *, + void *, void *) +STUB_FUNC1(_pthread_cancel_enter, PJT_CANCEL_ENTER, void, int) +STUB_FUNC1(_pthread_cancel_leave, PJT_CANCEL_LEAVE, void, int) +STUB_FUNC2(pthread_attr_get_np, PJT_ATTR_GET_NP, int, pthread_t, pthread_attr_t *) +STUB_FUNC3(pthread_getname_np, PJT_GETNAME_NP, int, pthread_t, char *, size_t) +STUB_FUNC(pthread_suspend_all_np, PJT_SUSPEND_ALL_NP, void); +STUB_FUNC(pthread_resume_all_np, PJT_RESUME_ALL_NP, void); + +static int +stub_zero(void) +{ + return (0); +} + +static void +stub_void(void) +{ + +} + +static void * +stub_null(void) +{ + return (NULL); +} + +static struct pthread * +stub_self(void) +{ + return (&main_thread); +} + +static int +stub_fail(void) +{ + return (ENOSYS); +} + +static int +stub_main(void) +{ + return (-1); +} + +static int +stub_true(void) +{ + return (1); +} + +static void +stub_exit(void) +{ + exit(0); +} + +static int +stub_esrch(void) +{ + return (ESRCH); +} + +static int +stub_getname_np(pthread_t thread, char *buf, size_t len) +{ + if (thread != &main_thread) + return (ESRCH); + if (len >= 1) + buf[0] = '\0'; + return (0); +} diff --git a/lib/libc/gen/_rand48.c b/lib/libc/gen/_rand48.c new file mode 100644 index 000000000000..114c1595b33d --- /dev/null +++ b/lib/libc/gen/_rand48.c @@ -0,0 +1,18 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +uint48 _rand48_seed = RAND48_SEED; +uint48 _rand48_mult = RAND48_MULT; +uint48 _rand48_add = RAND48_ADD; diff --git a/lib/libc/gen/_spinlock_stub.c b/lib/libc/gen/_spinlock_stub.c new file mode 100644 index 000000000000..30e5c61f5f74 --- /dev/null +++ b/lib/libc/gen/_spinlock_stub.c @@ -0,0 +1,77 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> + +#include "spinlock.h" +#include "libc_private.h" + +long _atomic_lock_stub(volatile long *); +void _spinlock_stub(spinlock_t *); +void _spinunlock_stub(spinlock_t *); + +__weak_reference(_atomic_lock_stub, _atomic_lock); + +long +_atomic_lock_stub(volatile long *lck __unused) +{ + return (0L); +} + +#pragma weak _spinlock +void +_spinlock(spinlock_t *lck) +{ + + ((void (*)(spinlock_t *lck))__libc_interposing[INTERPOS_spinlock]) + (lck); + +} + +#pragma weak _spinunlock +void +_spinunlock(spinlock_t *lck) +{ + + ((void (*)(spinlock_t *lck))__libc_interposing[INTERPOS_spinunlock]) + (lck); + +} + +void +__libc_spinlock_stub(spinlock_t *lck __unused) +{ +} + +void +__libc_spinunlock_stub(spinlock_t *lck __unused) +{ +} diff --git a/lib/libc/gen/_thread_init.c b/lib/libc/gen/_thread_init.c new file mode 100644 index 000000000000..66fa8b8c2e96 --- /dev/null +++ b/lib/libc/gen/_thread_init.c @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +void _thread_init_stub(void); + +__weak_reference(_thread_init_stub, _thread_init); +__weak_reference(_thread_autoinit_dummy_decl_stub, + _thread_autoinit_dummy_decl); + +int _thread_autoinit_dummy_decl_stub = 0; + +void +_thread_init_stub(void) +{ + /* This is just a stub; there is nothing to do. */ +} diff --git a/lib/libc/gen/aio_read2.c b/lib/libc/gen/aio_read2.c new file mode 100644 index 000000000000..a5186d509b26 --- /dev/null +++ b/lib/libc/gen/aio_read2.c @@ -0,0 +1,58 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 The FreeBSD Foundation + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/aio.h> +#include <errno.h> +#include <stddef.h> + +int +aio_read2(struct aiocb *iocb, int flags) +{ + int error; + + if ((flags & ~(AIO_OP2_FOFFSET | AIO_OP2_VECTORED)) != 0) { + errno = EINVAL; + return (-1); + } + iocb->aio_lio_opcode = LIO_READ; + if ((flags & AIO_OP2_FOFFSET) != 0) + iocb->aio_lio_opcode |= LIO_FOFFSET; + if ((flags & AIO_OP2_VECTORED) != 0) + iocb->aio_lio_opcode |= LIO_VECTORED; + + error = lio_listio(LIO_NOWAIT, &iocb, 1, NULL); + if (error == -1 && errno == EIO) { + error = aio_error(iocb); + if (error != -1 && error != 0) + errno = error; + error = -1; + } + return (error); +} diff --git a/lib/libc/gen/aio_write2.c b/lib/libc/gen/aio_write2.c new file mode 100644 index 000000000000..8f4f6a35fd4d --- /dev/null +++ b/lib/libc/gen/aio_write2.c @@ -0,0 +1,58 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2024 The FreeBSD Foundation + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/aio.h> +#include <errno.h> +#include <stddef.h> + +int +aio_write2(struct aiocb *iocb, int flags) +{ + int error; + + if ((flags & ~(AIO_OP2_FOFFSET | AIO_OP2_VECTORED)) != 0) { + errno = EINVAL; + return (-1); + } + iocb->aio_lio_opcode = LIO_WRITE; + if ((flags & AIO_OP2_FOFFSET) != 0) + iocb->aio_lio_opcode |= LIO_FOFFSET; + if ((flags & AIO_OP2_VECTORED) != 0) + iocb->aio_lio_opcode |= LIO_VECTORED; + + error = lio_listio(LIO_NOWAIT, &iocb, 1, NULL); + if (error == -1 && errno == EIO) { + error = aio_error(iocb); + if (error != -1 && error != 0) + errno = error; + error = -1; + } + return (error); +} diff --git a/lib/libc/gen/alarm.3 b/lib/libc/gen/alarm.3 new file mode 100644 index 000000000000..4a24cc6d7216 --- /dev/null +++ b/lib/libc/gen/alarm.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 1980, 1991, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 2, 2022 +.Dt ALARM 3 +.Os +.Sh NAME +.Nm alarm +.Nd set signal timer alarm +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft unsigned int +.Fn alarm "unsigned int seconds" +.Sh DESCRIPTION +.Bf -symbolic +This interface is made obsolete by +.Xr setitimer 2 . +.Ef +.Pp +The +.Fn alarm +function sets a timer to deliver the signal +.Dv SIGALRM +to the calling process after the specified number of +.Fa seconds . +If an alarm has already been set with +.Fn alarm +but has not been delivered, another call to +.Fn alarm +will supersede the prior call. +The request +.Fn alarm "0" +voids the current +alarm and the signal SIGALRM will not be delivered. +.Pp +Due to +.Xr setitimer 2 +restriction the maximum number of +.Fa seconds +allowed is 100,000,000. +.Sh RETURN VALUES +The return value of +.Fn alarm +is the amount of time left on the timer from a previous call to +.Fn alarm . +If no alarm is currently set, the return value is 0. +.Sh SEE ALSO +.Xr setitimer 2 , +.Xr sigaction 2 , +.Xr sigsuspend 2 , +.Xr signal 3 , +.Xr sleep 3 , +.Xr ualarm 3 , +.Xr usleep 3 +.\" .Sh STANDARDS +.\" The +.\" .Fn alarm +.\" function conforms to +.\" .St -p1003.1-90 . +.Sh HISTORY +An +.Fn alarm +system call appeared in the Programmer's Workbench (PWB/UNIX) +and was ported to +.At v7 . +For +.Bx 4.1c , +it was reimplemented as a wrapper around the +.Xr setitimer 2 +system call. diff --git a/lib/libc/gen/alarm.c b/lib/libc/gen/alarm.c new file mode 100644 index 000000000000..043571ff89a1 --- /dev/null +++ b/lib/libc/gen/alarm.c @@ -0,0 +1,52 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Backwards compatible alarm. + */ +#include <sys/time.h> +#include <unistd.h> + +unsigned int +alarm(unsigned int secs) +{ + struct itimerval it, oitv; + struct itimerval *itp = ⁢ + + timerclear(&itp->it_interval); + itp->it_value.tv_sec = secs; + itp->it_value.tv_usec = 0; + if (setitimer(ITIMER_REAL, itp, &oitv) < 0) + return (-1); + if (oitv.it_value.tv_usec) + oitv.it_value.tv_sec++; + return (oitv.it_value.tv_sec); +} diff --git a/lib/libc/gen/arc4random-compat.c b/lib/libc/gen/arc4random-compat.c new file mode 100644 index 000000000000..beeb4d75964a --- /dev/null +++ b/lib/libc/gen/arc4random-compat.c @@ -0,0 +1,67 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 Google LLC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <stdbool.h> +#include <syslog.h> + +/* + * The following functions were removed from OpenBSD for good reasons: + * + * - arc4random_stir() + * - arc4random_addrandom() + * + * On FreeBSD, for backward ABI compatibility, we provide two wrapper which + * logs this event and returns. + */ + +void __arc4random_stir_fbsd11(void); +void __arc4random_addrandom_fbsd11(u_char *, int); + +void +__arc4random_stir_fbsd11(void) +{ + static bool warned = false; + + if (!warned) + syslog(LOG_DEBUG, "Deprecated function arc4random_stir() called"); + warned = true; +} + +void +__arc4random_addrandom_fbsd11(u_char * dummy1 __unused, int dummy2 __unused) +{ + static bool warned = false; + + if (!warned) + syslog(LOG_DEBUG, "Deprecated function arc4random_addrandom() called"); + warned = true; +} + +__sym_compat(arc4random_stir, __arc4random_stir_fbsd11, FBSD_1.0); +__sym_compat(arc4random_addrandom, __arc4random_addrandom_fbsd11, FBSD_1.0); diff --git a/lib/libc/gen/arc4random.3 b/lib/libc/gen/arc4random.3 new file mode 100644 index 000000000000..1b042f15f000 --- /dev/null +++ b/lib/libc/gen/arc4random.3 @@ -0,0 +1,173 @@ +.\" $OpenBSD: arc4random.3,v 1.37 2019/09/29 16:30:35 jmc Exp $ +.\" +.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed by Niels Provos. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Manual page, using -mandoc macros +.\" +.Dd November 18, 2024 +.Dt ARC4RANDOM 3 +.Os +.Sh NAME +.Nm arc4random , +.Nm arc4random_buf , +.Nm arc4random_uniform +.Nd random number generator +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft uint32_t +.Fn arc4random "void" +.Ft void +.Fn arc4random_buf "void *buf" "size_t nbytes" +.Ft uint32_t +.Fn arc4random_uniform "uint32_t upper_bound" +.Sh DESCRIPTION +This family of functions provides higher quality data than those +described in +.Xr rand 3 , +.Xr random 3 , +and +.Xr rand48 3 . +.Pp +Use of these functions is encouraged for almost all random number +consumption because the other interfaces are deficient in either +quality, portability, standardization, or availability. +These functions can be called in almost all coding environments, +including +.Xr pthread 3 +and +.Xr chroot 2 . +.Pp +High quality 32-bit pseudo-random numbers are generated very quickly. +On each call, a cryptographic pseudo-random number generator is used +to generate a new result. +One data pool is used for all consumers in a process, so that consumption +under program flow can act as additional stirring. +The subsystem is re-seeded from the kernel +.Xr random 4 +subsystem using +.Xr getentropy 3 +on a regular basis, and also upon +.Xr fork 2 . +.Pp +The +.Fn arc4random +function returns a single 32-bit value. +The +.Fn arc4random +function returns pseudo-random numbers in the range of 0 to +.if t 2\u\s731\s10\d\(mi1, +.if n (2**32)\(mi1, +and therefore has twice the range of +.Xr rand 3 +and +.Xr random 3 . +.Pp +.Fn arc4random_buf +fills the region +.Fa buf +of length +.Fa nbytes +with random data. +.Pp +.Fn arc4random_uniform +will return a single 32-bit value, uniformly distributed but less than +.Fa upper_bound . +This is recommended over constructions like +.Dq Li arc4random() % upper_bound +as it avoids "modulo bias" when the upper bound is not a power of two. +In the worst case, this function may consume multiple iterations +to ensure uniformity; see the source code to understand the problem +and solution. +.Sh RETURN VALUES +These functions are always successful, and no return value is +reserved to indicate an error. +.Sh EXAMPLES +The following produces a drop-in replacement for the traditional +.Fn rand +and +.Fn random +functions using +.Fn arc4random : +.Pp +.Dl "#define foo4random() (arc4random_uniform(RAND_MAX + 1))" +.Sh SEE ALSO +.Xr rand 3 , +.Xr rand48 3 , +.Xr random 3 +.Rs +.%A Daniel J. Bernstein +.%T ChaCha, a variant of Salsa20 +.%D 2008-01-28 +.%O Document ID: 4027b5256e17b9796842e6d0f68b0b5e +.%U http://cr.yp.to/papers.html#chacha +.Re +.Rs +.%A Daniel Lemire +.%T Fast Random Integer Generation in an Interval +.%D January 2019 +.%J ACM Trans. Model. Comput. Simul. +.%I Association for Computing Machinery +.%C New York, NY, USA +.%V vol. 29 +.%N no. 1 +.%P pp. 1\(en12 +.Re +.Sh HISTORY +These functions first appeared in +.Ox 2.1 . +.Fn arc4random +first appeared in +.Fx 3.0 . +.Fn arc4random_buf +and +.Fn arc4random_uniform +first appeared in +.Fx 8.0 . +.Fn arc4random_stir +was removed in +.Fx 12.0 . +.Pp +The original version of this random number generator used the +RC4 (also known as ARC4) algorithm. +In +.Ox 5.5 +it was replaced with the ChaCha20 cipher, and it may be replaced +again in the future as cryptographic techniques advance. +A good mnemonic is +.Dq A Replacement Call for Random . +.Pp +The +.Fn arc4random +random number generator was first introduced in +.Fx 2.2.6 . +The ChaCha20 based implementation was introduced in +.Fx 12.0 , +with obsolete stir and addrandom interfaces removed at the same time. diff --git a/lib/libc/gen/arc4random.c b/lib/libc/gen/arc4random.c new file mode 100644 index 000000000000..cc65e0131970 --- /dev/null +++ b/lib/libc/gen/arc4random.c @@ -0,0 +1,252 @@ +/* $OpenBSD: arc4random.c,v 1.58 2022/07/31 13:41:45 tb Exp $ */ + +/* + * Copyright (c) 1996, David Mazieres <dm@uun.org> + * Copyright (c) 2008, Damien Miller <djm@openbsd.org> + * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> + * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * ChaCha based random number generator for OpenBSD. + */ + +#include "namespace.h" +#if defined(__FreeBSD__) +#include <assert.h> +#endif +#include <fcntl.h> +#include <limits.h> +#include <pthread.h> +#include <signal.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ssp/ssp.h> +#include <sys/types.h> +#include <sys/time.h> + +#include "libc_private.h" +#include "un-namespace.h" + +#define CHACHA_EMBED +#define KEYSTREAM_ONLY +#if defined(__FreeBSD__) +#define ARC4RANDOM_FXRNG 1 +#else +#define ARC4RANDOM_FXRNG 0 +#endif +#include "chacha.c" + +#define minimum(a, b) ((a) < (b) ? (a) : (b)) + +#if defined(__GNUC__) || defined(_MSC_VER) +#define inline __inline +#else /* __GNUC__ || _MSC_VER */ +#define inline +#endif /* !__GNUC__ && !_MSC_VER */ + +#define KEYSZ 32 +#define IVSZ 8 +#define BLOCKSZ 64 +#define RSBUFSZ (16*BLOCKSZ) + +#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */ + +/* Marked INHERIT_ZERO, so zero'd out in fork children. */ +static struct _rs { + size_t rs_have; /* valid bytes at end of rs_buf */ + size_t rs_count; /* bytes till reseed */ +} *rs; + +/* Maybe be preserved in fork children, if _rs_allocate() decides. */ +static struct _rsx { + chacha_ctx rs_chacha; /* chacha context for random keystream */ + u_char rs_buf[RSBUFSZ]; /* keystream blocks */ +#ifdef __FreeBSD__ + uint32_t rs_seed_generation; /* 32-bit userspace RNG version */ +#endif +} *rsx; + +static inline int _rs_allocate(struct _rs **, struct _rsx **); +static inline void _rs_forkdetect(void); +#include "arc4random.h" + +static inline void _rs_rekey(u_char *dat, size_t datlen); + +static inline void +_rs_init(u_char *buf, size_t n) +{ + if (n < KEYSZ + IVSZ) + return; + + if (rs == NULL) { + if (_rs_allocate(&rs, &rsx) == -1) + _exit(1); + } + + chacha_keysetup(&rsx->rs_chacha, buf, KEYSZ * 8); + chacha_ivsetup(&rsx->rs_chacha, buf + KEYSZ, NULL); +} + +static void +_rs_stir(void) +{ + u_char rnd[KEYSZ + IVSZ]; + uint32_t rekey_fuzz = 0; + +#if defined(__FreeBSD__) + bool need_init; + + /* + * De-couple allocation (which locates the vdso_fxrngp pointer in + * auxinfo) from initialization. This allows us to read the root seed + * version before we fetch system entropy, maintaining the invariant + * that the PRF was seeded with entropy from rs_seed_generation or a + * later generation. But never seeded from an earlier generation. + * This invariant prevents us from missing a root reseed event. + */ + need_init = false; + if (rs == NULL) { + if (_rs_allocate(&rs, &rsx) == -1) + abort(); + need_init = true; + } + /* + * Transition period: new userspace on old kernel. This should become + * a hard error at some point, if the scheme is adopted. + */ + if (vdso_fxrngp != NULL) + rsx->rs_seed_generation = + fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32); +#endif + + if (getentropy(rnd, sizeof rnd) == -1) + _getentropy_fail(); + +#if !defined(__FreeBSD__) + if (!rs) + _rs_init(rnd, sizeof(rnd)); +#else /* __FreeBSD__ */ + assert(rs != NULL); + if (need_init) + _rs_init(rnd, sizeof(rnd)); +#endif + else + _rs_rekey(rnd, sizeof(rnd)); + explicit_bzero(rnd, sizeof(rnd)); /* discard source seed */ + + /* invalidate rs_buf */ + rs->rs_have = 0; + memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); + + /* rekey interval should not be predictable */ + chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz, + (uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz)); + rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE); +} + +static inline void +_rs_stir_if_needed(size_t len) +{ + _rs_forkdetect(); + if (!rs || rs->rs_count <= len) + _rs_stir(); + if (rs->rs_count <= len) + rs->rs_count = 0; + else + rs->rs_count -= len; +} + +static inline void +_rs_rekey(u_char *dat, size_t datlen) +{ +#ifndef KEYSTREAM_ONLY + memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf)); +#endif + /* fill rs_buf with the keystream */ + chacha_encrypt_bytes(&rsx->rs_chacha, rsx->rs_buf, + rsx->rs_buf, sizeof(rsx->rs_buf)); + /* mix in optional user provided data */ + if (dat) { + size_t i, m; + + m = minimum(datlen, KEYSZ + IVSZ); + for (i = 0; i < m; i++) + rsx->rs_buf[i] ^= dat[i]; + } + /* immediately reinit for backtracking resistance */ + _rs_init(rsx->rs_buf, KEYSZ + IVSZ); + memset(rsx->rs_buf, 0, KEYSZ + IVSZ); + rs->rs_have = sizeof(rsx->rs_buf) - KEYSZ - IVSZ; +} + +static inline void +_rs_random_buf(void *_buf, size_t n) +{ + u_char *buf = (u_char *)_buf; + u_char *keystream; + size_t m; + + _rs_stir_if_needed(n); + while (n > 0) { + if (rs->rs_have > 0) { + m = minimum(n, rs->rs_have); + keystream = rsx->rs_buf + sizeof(rsx->rs_buf) + - rs->rs_have; + memcpy(buf, keystream, m); + memset(keystream, 0, m); + buf += m; + n -= m; + rs->rs_have -= m; + } + if (rs->rs_have == 0) + _rs_rekey(NULL, 0); + } +} + +static inline void +_rs_random_u32(uint32_t *val) +{ + u_char *keystream; + + _rs_stir_if_needed(sizeof(*val)); + if (rs->rs_have < sizeof(*val)) + _rs_rekey(NULL, 0); + keystream = rsx->rs_buf + sizeof(rsx->rs_buf) - rs->rs_have; + memcpy(val, keystream, sizeof(*val)); + memset(keystream, 0, sizeof(*val)); + rs->rs_have -= sizeof(*val); +} + +uint32_t +arc4random(void) +{ + uint32_t val; + + _ARC4_LOCK(); + _rs_random_u32(&val); + _ARC4_UNLOCK(); + return val; +} + +void +__ssp_real(arc4random_buf)(void *buf, size_t n) +{ + _ARC4_LOCK(); + _rs_random_buf(buf, n); + _ARC4_UNLOCK(); +} diff --git a/lib/libc/gen/arc4random.h b/lib/libc/gen/arc4random.h new file mode 100644 index 000000000000..e6332f155db2 --- /dev/null +++ b/lib/libc/gen/arc4random.h @@ -0,0 +1,148 @@ +/* $OpenBSD: arc4random.h,v 1.4 2015/01/15 06:57:18 deraadt Exp $ */ + +/* + * Copyright (c) 1996, David Mazieres <dm@uun.org> + * Copyright (c) 2008, Damien Miller <djm@openbsd.org> + * Copyright (c) 2013, Markus Friedl <markus@openbsd.org> + * Copyright (c) 2014, Theo de Raadt <deraadt@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Stub functions for portability. + */ +#include <sys/elf.h> +#include <sys/endian.h> +#include <sys/mman.h> +#if ARC4RANDOM_FXRNG != 0 +#include <sys/time.h> /* for sys/vdso.h only. */ +#include <sys/vdso.h> +#include <machine/atomic.h> +#endif + +#include <err.h> +#include <errno.h> +#include <signal.h> +#include <stdbool.h> +#include <stdint.h> + +#if ARC4RANDOM_FXRNG != 0 +/* + * The kernel root seed version is a 64-bit counter, but we truncate it to a + * 32-bit value in userspace for the convenience of 32-bit platforms. 32-bit + * rollover is not possible with the current reseed interval (1 hour at limit) + * without dynamic addition of new random devices (which also force a reseed in + * the FXRNG design). We don't have any dynamic device mechanism at this + * time, and anyway something else is very wrong if billions of new devices are + * being added. + * + * As is, it takes roughly 456,000 years of runtime to overflow the 32-bit + * version. + */ +#define fxrng_load_acq_generation(x) atomic_load_acq_32(x) +static struct vdso_fxrng_generation_1 *vdso_fxrngp; +#endif + +static pthread_mutex_t arc4random_mtx = PTHREAD_MUTEX_INITIALIZER; +#define _ARC4_LOCK() \ + do { \ + if (__isthreaded) \ + _pthread_mutex_lock(&arc4random_mtx); \ + } while (0) + +#define _ARC4_UNLOCK() \ + do { \ + if (__isthreaded) \ + _pthread_mutex_unlock(&arc4random_mtx); \ + } while (0) + +static inline void +_getentropy_fail(void) +{ + raise(SIGKILL); +} + +static inline void +_rs_initialize_fxrng(void) +{ +#if ARC4RANDOM_FXRNG != 0 + struct vdso_fxrng_generation_1 *fxrngp; + int error; + + error = _elf_aux_info(AT_FXRNG, &fxrngp, sizeof(fxrngp)); + if (error != 0) { + /* + * New userspace on an old or !RANDOM_FENESTRASX kernel; or an + * arch that does not have a VDSO page. + */ + return; + } + + /* Old userspace on newer kernel. */ + if (fxrngp->fx_vdso_version != VDSO_FXRNG_VER_1) + return; + + vdso_fxrngp = fxrngp; +#endif +} + +static inline int +_rs_allocate(struct _rs **rsp, struct _rsx **rsxp) +{ + struct { + struct _rs rs; + struct _rsx rsx; + } *p; + + if ((p = mmap(NULL, sizeof(*p), PROT_READ|PROT_WRITE, + MAP_ANON|MAP_PRIVATE, -1, 0)) == MAP_FAILED) + return (-1); + /* Allow bootstrapping arc4random.c on Linux/macOS */ +#ifdef INHERIT_ZERO + if (minherit(p, sizeof(*p), INHERIT_ZERO) == -1) { + munmap(p, sizeof(*p)); + return (-1); + } +#endif + + _rs_initialize_fxrng(); + + *rsp = &p->rs; + *rsxp = &p->rsx; + return (0); +} + +/* + * This isn't only detecting fork. We're also using the existing callback from + * _rs_stir_if_needed() to force arc4random(3) to reseed if the fenestrasX root + * seed version has changed. (That is, the root random(4) has reseeded from + * pooled entropy.) + */ +static inline void +_rs_forkdetect(void) +{ + /* Detect fork (minherit(2) INHERIT_ZERO). */ + if (__predict_false(rs == NULL || rsx == NULL)) + return; +#if ARC4RANDOM_FXRNG != 0 + /* If present, detect kernel FenestrasX seed version change. */ + if (vdso_fxrngp == NULL) + return; + if (__predict_true(rsx->rs_seed_generation == + fxrng_load_acq_generation(&vdso_fxrngp->fx_generation32))) + return; +#endif + /* Invalidate rs_buf to force "stir" (reseed). */ + memset(rs, 0, sizeof(*rs)); +} diff --git a/lib/libc/gen/arc4random_uniform.c b/lib/libc/gen/arc4random_uniform.c new file mode 100644 index 000000000000..23455e545899 --- /dev/null +++ b/lib/libc/gen/arc4random_uniform.c @@ -0,0 +1,47 @@ +/*- + * SPDX-License-Identifier: 0BSD + * + * Copyright (c) Robert Clausecker <fuz@FreeBSD.org> + * Based on a publication by Daniel Lemire. + * Public domain where applicable. + * + * Daniel Lemire, "Fast Random Integer Generation in an Interval", + * Association for Computing Machinery, ACM Trans. Model. Comput. Simul., + * no. 1, vol. 29, pp. 1--12, New York, NY, USA, January 2019. + */ + +#include <stdint.h> +#include <stdlib.h> + +uint32_t +arc4random_uniform(uint32_t upper_bound) +{ + uint64_t product; + + /* + * The paper uses these variable names: + * + * L -- log2(UINT32_MAX+1) + * s -- upper_bound + * x -- arc4random() return value + * m -- product + * l -- (uint32_t)product + * t -- threshold + */ + + if (upper_bound <= 1) + return (0); + + product = upper_bound * (uint64_t)arc4random(); + + if ((uint32_t)product < upper_bound) { + uint32_t threshold; + + /* threshold = (2**32 - upper_bound) % upper_bound */ + threshold = -upper_bound % upper_bound; + while ((uint32_t)product < threshold) + product = upper_bound * (uint64_t)arc4random(); + } + + return (product >> 32); +} diff --git a/lib/libc/gen/assert.c b/lib/libc/gen/assert.c new file mode 100644 index 000000000000..21e5a44522ec --- /dev/null +++ b/lib/libc/gen/assert.c @@ -0,0 +1,49 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +void +__assert(const char *func, const char *file, int line, const char *failedexpr) +{ + if (func == NULL) + (void)fprintf(stderr, + "Assertion failed: (%s), file %s, line %d.\n", failedexpr, + file, line); + else + (void)fprintf(stderr, + "Assertion failed: (%s), function %s, file %s, line %d.\n", + failedexpr, func, file, line); + abort(); + /* NOTREACHED */ +} diff --git a/lib/libc/gen/basename.3 b/lib/libc/gen/basename.3 new file mode 100644 index 000000000000..e3fb25606172 --- /dev/null +++ b/lib/libc/gen/basename.3 @@ -0,0 +1,86 @@ +.\" $OpenBSD: basename.3,v 1.20 2007/05/31 19:19:28 jmc Exp $ +.\" +.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd May 22, 2017 +.Dt BASENAME 3 +.Os +.Sh NAME +.Nm basename +.Nd extract the base portion of a pathname +.Sh SYNOPSIS +.In libgen.h +.Ft char * +.Fn basename "char *path" +.Sh DESCRIPTION +The +.Fn basename +function returns the last component from the pathname pointed to by +.Fa path , +deleting any trailing +.Sq \&/ +characters. +.Sh IMPLEMENTATION NOTES +This implementation of +.Fn basename +uses the buffer provided by the caller to store the resulting pathname +component. +Other vendor implementations may return a pointer to internal storage +space instead. +The advantage of the former approach is that it ensures thread-safety, +while also placing no upper limit on the supported length of the +pathname. +.Sh RETURN VALUES +If +.Fa path +consists entirely of +.Sq \&/ +characters, a pointer to the string +.Qq \&/ +is returned. +If +.Fa path +is a null pointer or the empty string, a pointer to the string +.Qq \&. +is returned. +Otherwise, +it returns a pointer to the last component of +.Fa path . +.Sh SEE ALSO +.Xr basename 1 , +.Xr dirname 1 , +.Xr dirname 3 +.Sh STANDARDS +The +.Fn basename +function conforms to +.St -xpg4.2 . +.Sh HISTORY +The +.Fn basename +function first appeared in +.Ox 2.2 +and +.Fx 4.2 . +.Pp +In +.Fx 12.0 , +this function was reimplemented to store its result in the provided +input buffer. +There is no longer any need to use the +.Fn basename_r +function. +.Sh AUTHORS +.An Nuxi, the Netherlands diff --git a/lib/libc/gen/basename.c b/lib/libc/gen/basename.c new file mode 100644 index 000000000000..d0ba1bd9229c --- /dev/null +++ b/lib/libc/gen/basename.c @@ -0,0 +1,51 @@ +/*- + * Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <libgen.h> +#include <string.h> + +char * +(basename)(char *path) +{ + char *ptr; + + /* + * If path is a null pointer or points to an empty string, + * basename() shall return a pointer to the string ".". + */ + if (path == NULL || *path == '\0') + return (__DECONST(char *, ".")); + + /* Find end of last pathname component and null terminate it. */ + ptr = path + strlen(path); + while (ptr > path + 1 && *(ptr - 1) == '/') + --ptr; + *ptr-- = '\0'; + + /* Find beginning of last pathname component. */ + while (ptr > path && *(ptr - 1) != '/') + --ptr; + return (ptr); +} diff --git a/lib/libc/gen/basename_compat.c b/lib/libc/gen/basename_compat.c new file mode 100644 index 000000000000..19a4bd6c03eb --- /dev/null +++ b/lib/libc/gen/basename_compat.c @@ -0,0 +1,82 @@ +/* $OpenBSD: basename.c,v 1.14 2005/08/08 08:05:33 espie Exp $ */ + +/* + * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <libgen.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +char * __freebsd11_basename_r(const char *path, char *bname); +char * __freebsd11_basename(char *path); + +char * +__freebsd11_basename_r(const char *path, char *bname) +{ + const char *endp, *startp; + size_t len; + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + bname[0] = '.'; + bname[1] = '\0'; + return (bname); + } + + /* Strip any trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* All slashes becomes "/" */ + if (endp == path && *endp == '/') { + bname[0] = '/'; + bname[1] = '\0'; + return (bname); + } + + /* Find the start of the base */ + startp = endp; + while (startp > path && *(startp - 1) != '/') + startp--; + + len = endp - startp + 1; + if (len >= MAXPATHLEN) { + errno = ENAMETOOLONG; + return (NULL); + } + memcpy(bname, startp, len); + bname[len] = '\0'; + return (bname); +} + +char * +__freebsd11_basename(char *path) +{ + static char *bname = NULL; + + if (bname == NULL) { + bname = (char *)malloc(MAXPATHLEN); + if (bname == NULL) + return (NULL); + } + return (__freebsd11_basename_r(path, bname)); +} + +__sym_compat(basename_r, __freebsd11_basename_r, FBSD_1.2); +__sym_compat(basename, __freebsd11_basename, FBSD_1.0); diff --git a/lib/libc/gen/cap_rights_get.3 b/lib/libc/gen/cap_rights_get.3 new file mode 100644 index 000000000000..e99424c7afdc --- /dev/null +++ b/lib/libc/gen/cap_rights_get.3 @@ -0,0 +1,120 @@ +.\" +.\" Copyright (c) 2013 The FreeBSD Foundation +.\" +.\" This documentation was written by Pawel Jakub Dawidek under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 5, 2020 +.Dt CAP_RIGHTS_GET 3 +.Os +.Sh NAME +.Nm cap_rights_get +.Nd obtain capability rights +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/capsicum.h +.Ft int +.Fn cap_rights_get "int fd" "cap_rights_t *rights" +.Sh DESCRIPTION +The +.Nm cap_rights_get +function allows to obtain current capability rights for the given descriptor. +The function will fill the +.Fa rights +argument with all capability rights if they were not limited or capability +rights configured during the last successful call of +.Xr cap_rights_limit 2 +on the given descriptor. +.Pp +The +.Fa rights +argument can be inspected using +.Xr cap_rights_init 3 +family of functions. +.Pp +The complete list of the capability rights can be found in the +.Xr rights 4 +manual page. +.Sh RETURN VALUES +.Rv -std +.Sh EXAMPLES +The following example demonstrates how to limit file descriptor capability +rights and how to obtain them. +.Bd -literal +cap_rights_t setrights, getrights; +int fd; + +memset(&setrights, 0, sizeof(setrights)); +memset(&getrights, 0, sizeof(getrights)); + +fd = open("/tmp/foo", O_RDONLY); +if (fd < 0) + err(1, "open() failed"); + +cap_rights_init(&setrights, CAP_FSTAT, CAP_READ); +if (cap_rights_limit(fd, &setrights) < 0 && errno != ENOSYS) + err(1, "cap_rights_limit() failed"); + +if (cap_rights_get(fd, &getrights) < 0 && errno != ENOSYS) + err(1, "cap_rights_get() failed"); + +assert(memcmp(&setrights, &getrights, sizeof(setrights)) == 0); +.Ed +.Sh ERRORS +.Fn cap_rights_get +succeeds unless: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid active descriptor. +.It Bq Er EFAULT +The +.Fa rights +argument points at an invalid address. +.El +.Sh SEE ALSO +.Xr cap_rights_limit 2 , +.Xr errno 2 , +.Xr open 2 , +.Xr assert 3 , +.Xr cap_rights_init 3 , +.Xr err 3 , +.Xr memcmp 3 , +.Xr memset 3 , +.Xr capsicum 4 , +.Xr rights 4 +.Sh HISTORY +The +.Fn cap_rights_get +function first appeared in +.Fx 9.2 . +Support for capabilities and capabilities mode was developed as part of the +.Tn TrustedBSD +Project. +.Sh AUTHORS +This function was created by +.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net +under sponsorship of the FreeBSD Foundation. diff --git a/lib/libc/gen/cap_sandboxed.3 b/lib/libc/gen/cap_sandboxed.3 new file mode 100644 index 000000000000..6e2004fb7a29 --- /dev/null +++ b/lib/libc/gen/cap_sandboxed.3 @@ -0,0 +1,73 @@ +.\" +.\" Copyright (c) 2012 The FreeBSD Foundation +.\" +.\" This documentation was written by Pawel Jakub Dawidek under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 5, 2020 +.Dt CAP_SANDBOXED 3 +.Os +.Sh NAME +.Nm cap_sandboxed +.Nd Check if in a capability mode sandbox +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/capsicum.h +.In stdbool.h +.Ft bool +.Fn cap_sandboxed "void" +.Sh DESCRIPTION +.Fn cap_sandboxed +returns +.Va true +if the process is in a capability mode sandbox or +.Va false +if it is not. +This function is a more handy alternative to the +.Xr cap_getmode 2 +system call as it always succeeds, so there is no need for error checking. +If the support for capability mode is not compiled into the kernel, +.Fn cap_sandboxed +will always return +.Va false . +.Sh RETURN VALUES +Function +.Fn cap_sandboxed +is always successful and will return either +.Va true +or +.Va false . +.Sh SEE ALSO +.Xr cap_enter 2 , +.Xr capsicum 4 +.Sh HISTORY +The +.Fn cap_sandboxed +function first appeared in +.Fx 9.2 . +.Sh AUTHORS +This function was implemented and manual page was written by +.An Pawel Jakub Dawidek Aq Mt pawel@dawidek.net +under sponsorship of the FreeBSD Foundation. diff --git a/lib/libc/gen/cap_sandboxed.c b/lib/libc/gen/cap_sandboxed.c new file mode 100644 index 000000000000..63c2439382a6 --- /dev/null +++ b/lib/libc/gen/cap_sandboxed.c @@ -0,0 +1,48 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 The FreeBSD Foundation + * + * This software was developed by Pawel Jakub Dawidek under sponsorship from + * the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/capsicum.h> + +#include <assert.h> +#include <errno.h> +#include <stdbool.h> + +bool +cap_sandboxed(void) +{ + u_int mode; + + if (cap_getmode(&mode) != 0) { + assert(errno == ENOSYS); + return (false); + } + assert(mode == 0 || mode == 1); + return (mode == 1); +} diff --git a/lib/libc/gen/check_utility_compat.3 b/lib/libc/gen/check_utility_compat.3 new file mode 100644 index 000000000000..05dea4f124b6 --- /dev/null +++ b/lib/libc/gen/check_utility_compat.3 @@ -0,0 +1,87 @@ +.\" +.\" Copyright 2002 Massachusetts Institute of Technology +.\" +.\" Permission to use, copy, modify, and distribute this software and +.\" its documentation for any purpose and without fee is hereby +.\" granted, provided that both the above copyright notice and this +.\" permission notice appear in all copies, that both the above +.\" copyright notice and this permission notice appear in all +.\" supporting documentation, and that the name of M.I.T. not be used +.\" in advertising or publicity pertaining to distribution of the +.\" software without specific, written prior permission. M.I.T. makes +.\" no representations about the suitability of this software for any +.\" purpose. It is provided "as is" without express or implied +.\" warranty. +.\" +.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS +.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT +.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 27, 2002 +.Dt CHECK_UTILITY_COMPAT 3 +.Os +.Sh NAME +.Nm check_utility_compat +.Nd "determine whether a utility should be compatible" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn check_utility_compat "const char *utility" +.Sh DESCRIPTION +The +.Fn check_utility_compat +function checks whether +.Fa utility +should behave in a traditional +.Pq Fx 4.7 Ns -compatible +manner, or in accordance with +.St -p1003.1-2001 . +The configuration is given as a comma-separated list of utility names; +if the list is present but empty, all supported utilities assume their +most compatible mode. +The +.Fn check_utility_compat +function first checks for an environment variable named +.Ev _COMPAT_FreeBSD_4 . +If that environment variable does not exist, then +.Fn check_utility_compat +will attempt to read the contents of a symbolic link named +.Pa /etc/compat-FreeBSD-4-util . +If no configuration is found, compatibility mode is disabled. +.Sh RETURN VALUES +The +.Fn check_utility_compat +function returns zero if +.Fa utility +should implement strict +.St -p1003.1-2001 +behavior, and nonzero otherwise. +.Sh FILES +.Bl -tag -width ".Pa /etc/compat-FreeBSD-4-util" +.It Pa /etc/compat-FreeBSD-4-util +If present, a symbolic link whose expansion gives system-wide default settings +for the +.Fn check_utility_compat +function. +.El +.Sh ERRORS +No errors are detected. +.Sh HISTORY +The +.Fn check_utility_compat +function first appeared in +.Fx 5.0 . +.Sh AUTHORS +This manual page was written by +.An Garrett Wollman Aq Mt wollman@FreeBSD.org . diff --git a/lib/libc/gen/check_utility_compat.c b/lib/libc/gen/check_utility_compat.c new file mode 100644 index 000000000000..63a268896daa --- /dev/null +++ b/lib/libc/gen/check_utility_compat.c @@ -0,0 +1,68 @@ +/* + * Copyright 2002 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * I din't use "namespace.h" here because none of the relevant utilities + * are threaded, so I'm not concerned about cancellation points or other + * niceties. + */ +#include <sys/limits.h> + +#include <limits.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define _PATH_UTIL_COMPAT "/etc/compat-FreeBSD-4-util" +#define _ENV_UTIL_COMPAT "_COMPAT_FreeBSD_4" + +int +check_utility_compat(const char *utility) +{ + char buf[PATH_MAX]; + char *p, *bp; + int len; + + if ((p = getenv(_ENV_UTIL_COMPAT)) != NULL) { + strlcpy(buf, p, sizeof buf); + } else { + if ((len = readlink(_PATH_UTIL_COMPAT, buf, sizeof(buf) - 1)) < 0) + return 0; + buf[len] = '\0'; + } + if (buf[0] == '\0') + return 1; + + bp = buf; + while ((p = strsep(&bp, ",")) != NULL) { + if (strcmp(p, utility) == 0) + return 1; + } + return 0; +} diff --git a/lib/libc/gen/clock.3 b/lib/libc/gen/clock.3 new file mode 100644 index 000000000000..77d7ce085d2e --- /dev/null +++ b/lib/libc/gen/clock.3 @@ -0,0 +1,73 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 4, 1993 +.Dt CLOCK 3 +.Os +.Sh NAME +.Nm clock +.Nd determine processor time used +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In time.h +.Ft clock_t +.Fn clock void +.Sh DESCRIPTION +The +.Fn clock +function +determines the amount of processor time used since the invocation of the +calling process, measured in +.Dv CLOCKS_PER_SEC Ns s +of a second. +.Sh RETURN VALUES +The +.Fn clock +function returns the amount of time used unless an error occurs, in which +case the return value is \-1. +.Sh SEE ALSO +.Xr getrusage 2 , +.Xr clocks 7 +.Sh STANDARDS +The +.Fn clock +function conforms to +.St -isoC . +However, +.St -susv2 +requires +.Dv CLOCKS_PER_SEC +to be defined as one million. +.Fx +does not conform to this requirement; +changing the value would introduce binary incompatibility +and one million is still inadequate on modern processors. diff --git a/lib/libc/gen/clock.c b/lib/libc/gen/clock.c new file mode 100644 index 000000000000..4d78fff73028 --- /dev/null +++ b/lib/libc/gen/clock.c @@ -0,0 +1,51 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/resource.h> + +/* + * Convert usec to clock ticks; could do (usec * CLOCKS_PER_SEC) / 1000000, + * but this would overflow if we switch to nanosec. + */ +#define CONVTCK(r) ((r).tv_sec * CLOCKS_PER_SEC \ + + (r).tv_usec / (1000000 / CLOCKS_PER_SEC)) + +clock_t +clock(void) +{ + struct rusage ru; + + if (getrusage(RUSAGE_SELF, &ru)) + return ((clock_t) -1); + return((clock_t)((CONVTCK(ru.ru_utime) + CONVTCK(ru.ru_stime)))); +} diff --git a/lib/libc/gen/clock_getcpuclockid.3 b/lib/libc/gen/clock_getcpuclockid.3 new file mode 100644 index 000000000000..b14c956be71d --- /dev/null +++ b/lib/libc/gen/clock_getcpuclockid.3 @@ -0,0 +1,95 @@ +.\" Copyright (c) 2012 David Xu <davidxu@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd August 21, 2012 +.Dt CLOCK_GETCPUCLOCKID 3 +.Os +.Sh NAME +.Nm clock_getcpuclockid +.Nd access a process CPU-time clock +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In time.h +.Ft int +.Fn clock_getcpuclockid "pid_t pid" "clockid_t *clock_id" +.Sh DESCRIPTION +The +.Fn clock_getcpuclockid +returns the clock ID of the CPU-time clock of the process specified by +.Fa pid . +If the process described by +.Fa pid +exists and the calling process has permission, the clock ID of this +clock will be returned in +.Fa clock_id . +.Pp +If +.Fa pid +is zero, the +.Fn clock_getcpuclockid +function returns the clock ID of the CPU-time clock of the process +making the call, in +.Fa clock_id . +.Sh RETURN VALUES +Upon successful completion, +.Fn clock_getcpuclockid +returns zero; otherwise, an error number is returned to indicate the +error. +.Sh ERRORS +The +.Fn clock_getcpuclockid +function will fail if: +.Bl -tag -width Er +.It Bq Er EPERM +The requesting process does not have permission to access the CPU-time +clock for the process. +.It Bq Er ESRCH +No process can be found corresponding to the process specified by +.Fa pid . +.El +.Sh SEE ALSO +.Xr clock_gettime 2 +.Sh STANDARDS +The +.Fn clock_getcpuclockid +function conforms to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn clock_getcpuclockid +function first appeared in +.Fx 10.0 . +.Sh AUTHORS +.An David Xu Aq Mt davidxu@FreeBSD.org diff --git a/lib/libc/gen/clock_getcpuclockid.c b/lib/libc/gen/clock_getcpuclockid.c new file mode 100644 index 000000000000..77d6c3423301 --- /dev/null +++ b/lib/libc/gen/clock_getcpuclockid.c @@ -0,0 +1,40 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 David Xu <davidxu@FreeBSD.org>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY DANIEL EISCHEN AND CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <errno.h> +#include <time.h> +#include <unistd.h> +#include <sys/time.h> + +int +clock_getcpuclockid(pid_t pid, clockid_t *clock_id) +{ + if (clock_getcpuclockid2(pid, CPUCLOCK_WHICH_PID, clock_id)) + return (errno); + return (0); +} diff --git a/lib/libc/gen/closedir.c b/lib/libc/gen/closedir.c new file mode 100644 index 000000000000..6015114d6c47 --- /dev/null +++ b/lib/libc/gen/closedir.c @@ -0,0 +1,73 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <dirent.h> +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "gen-private.h" +#include "telldir.h" + +/* + * close a directory. + */ +int +fdclosedir(DIR *dirp) +{ + int fd; + + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + fd = dirp->dd_fd; + dirp->dd_fd = -1; + dirp->dd_loc = 0; + free((void *)dirp->dd_buf); + free(dirp->dd_compat_de); + _reclaim_telldir(dirp); + if (__isthreaded) { + _pthread_mutex_unlock(&dirp->dd_lock); + _pthread_mutex_destroy(&dirp->dd_lock); + } + free((void *)dirp); + return (fd); +} + +int +closedir(DIR *dirp) +{ + + return (_close(fdclosedir(dirp))); +} diff --git a/lib/libc/gen/confstr.3 b/lib/libc/gen/confstr.3 new file mode 100644 index 000000000000..df19339c612a --- /dev/null +++ b/lib/libc/gen/confstr.3 @@ -0,0 +1,126 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd December 3, 2006 +.Dt CONFSTR 3 +.Os +.Sh NAME +.Nm confstr +.Nd get string-valued configurable variables +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft size_t +.Fn confstr "int name" "char *buf" "size_t len" +.Sh DESCRIPTION +This interface is specified by +.St -p1003.1-2001 . +A more flexible (but non-portable) interface is provided by +.Xr sysctl 3 . +.Pp +The +.Fn confstr +function provides a method for applications to get configuration +defined string values. +Shell programmers needing access to these parameters should use the +.Xr getconf 1 +utility. +.Pp +The +.Fa name +argument specifies the system variable to be queried. +Symbolic constants for each name value are found in the include file +.In unistd.h . +The +.Fa len +argument specifies the size of the buffer referenced by the +argument +.Fa buf . +If +.Fa len +is non-zero, +.Fa buf +is a non-null pointer, and +.Fa name +has a value, up to +.Fa len +\- 1 bytes of the value are copied into the buffer +.Fa buf . +The copied value is always null terminated. +.Pp +The available values are as follows: +.Bl -tag -width 6n +.It Li _CS_PATH +Return a value for the +.Ev PATH +environment variable that finds all the standard utilities. +.El +.Sh RETURN VALUES +If the call to +.Fn confstr +is not successful, 0 is returned and +.Va errno +is set appropriately. +Otherwise, if the variable does not have a configuration defined value, +0 is returned and +.Va errno +is not modified. +Otherwise, the buffer size needed to hold the entire configuration-defined +value is returned. +If this size is greater than the argument +.Fa len , +the string in +.Fa buf +was truncated. +.Sh ERRORS +The +.Fn confstr +function may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr malloc 3 +and +.Xr sysctl 3 . +.Pp +In addition, the following errors may be reported: +.Bl -tag -width Er +.It Bq Er EINVAL +The value of the +.Fa name +argument is invalid. +.El +.Sh SEE ALSO +.Xr getconf 1 , +.Xr pathconf 2 , +.Xr sysconf 3 , +.Xr sysctl 3 +.Sh HISTORY +The +.Fn confstr +function first appeared in +.Bx 4.4 . diff --git a/lib/libc/gen/confstr.c b/lib/libc/gen/confstr.c new file mode 100644 index 000000000000..491df0cba67a --- /dev/null +++ b/lib/libc/gen/confstr.c @@ -0,0 +1,117 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> + +#include <errno.h> +#include <limits.h> +#include <paths.h> +#include <string.h> +#include <unistd.h> + + +size_t +confstr(int name, char *buf, size_t len) +{ + const char *p; + const char UPE[] = "unsupported programming environment"; + + switch (name) { + case _CS_PATH: + p = _PATH_STDPATH; + goto docopy; + + /* + * POSIX/SUS ``Programming Environments'' stuff + * + * We don't support more than one programming environment + * on any platform (yet), so we just return the empty + * string for the environment we are compiled for, + * and the string "unsupported programming environment" + * for anything else. (The Standard says that if these + * values are used on a system which does not support + * this environment -- determined via sysconf() -- then + * the value we return is unspecified. So, we return + * something which will cause obvious breakage.) + */ + case _CS_POSIX_V6_ILP32_OFF32_CFLAGS: + case _CS_POSIX_V6_ILP32_OFF32_LDFLAGS: + case _CS_POSIX_V6_ILP32_OFF32_LIBS: + case _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS: + case _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS: + case _CS_POSIX_V6_LPBIG_OFFBIG_LIBS: + /* + * These two environments are never supported. + */ + p = UPE; + goto docopy; + + case _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS: + case _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS: + case _CS_POSIX_V6_ILP32_OFFBIG_LIBS: + if (sizeof(long) * CHAR_BIT == 32 && + sizeof(off_t) > sizeof(long)) + p = ""; + else + p = UPE; + goto docopy; + + case _CS_POSIX_V6_LP64_OFF64_CFLAGS: + case _CS_POSIX_V6_LP64_OFF64_LDFLAGS: + case _CS_POSIX_V6_LP64_OFF64_LIBS: + if (sizeof(long) * CHAR_BIT >= 64 && + sizeof(void *) * CHAR_BIT >= 64 && + sizeof(int) * CHAR_BIT >= 32 && + sizeof(off_t) >= sizeof(long)) + p = ""; + else + p = UPE; + goto docopy; + + case _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS: + /* XXX - should have more complete coverage */ + if (sizeof(long) * CHAR_BIT >= 64) + p = "_POSIX_V6_LP64_OFF64"; + else + p = "_POSIX_V6_ILP32_OFFBIG"; + goto docopy; + +docopy: + if (len != 0 && buf != NULL) + strlcpy(buf, p, len); + return (strlen(p) + 1); + + default: + errno = EINVAL; + return (0); + } + /* NOTREACHED */ +} diff --git a/lib/libc/gen/cpuset_alloc.c b/lib/libc/gen/cpuset_alloc.c new file mode 100644 index 000000000000..ac307f07f263 --- /dev/null +++ b/lib/libc/gen/cpuset_alloc.c @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2021 Stefan Esser <se@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <sched.h> + +cpuset_t * +__cpuset_alloc(size_t ncpus) +{ + return (malloc(CPU_ALLOC_SIZE(ncpus))); +} diff --git a/lib/libc/gen/cpuset_free.c b/lib/libc/gen/cpuset_free.c new file mode 100644 index 000000000000..4cd993853241 --- /dev/null +++ b/lib/libc/gen/cpuset_free.c @@ -0,0 +1,33 @@ +/*- + * Copyright (c) 2021 Stefan Esser <se@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <sched.h> + +void +__cpuset_free(cpuset_t *ptr) +{ + free(ptr); +} diff --git a/lib/libc/gen/crypt.c b/lib/libc/gen/crypt.c new file mode 100644 index 000000000000..ddcd6719775f --- /dev/null +++ b/lib/libc/gen/crypt.c @@ -0,0 +1,88 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Tom Truscott. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +/* + * UNIX password, and DES, encryption. + * + * since this is non-exportable, this is just a dummy. if you want real + * encryption, make sure you've got libcrypt.a around. + */ + +int __freebsd11_des_setkey(const char *key); +int __freebsd11_des_cipher(const char *in, char *out, long salt, int num_iter); +int __freebsd11_setkey(const char *key); +int __freebsd11_encrypt(char *block, int flag); + +/* ARGSUSED */ +int +__freebsd11_des_setkey(const char *key __unused) +{ + fprintf(stderr, "WARNING! des_setkey(3) not present in the system!\n"); + return (0); +} + +/* ARGSUSED */ +int +__freebsd11_des_cipher(const char *in, char *out, long salt __unused, + int num_iter __unused) +{ + fprintf(stderr, "WARNING! des_cipher(3) not present in the system!\n"); + bcopy(in, out, 8); + return (0); +} + +/* ARGSUSED */ +int +__freebsd11_setkey(const char *key __unused) +{ + fprintf(stderr, "WARNING! setkey(3) not present in the system!\n"); + return (0); +} + +/* ARGSUSED */ +int +__freebsd11_encrypt(char *block __unused, int flag __unused) +{ + fprintf(stderr, "WARNING! encrypt(3) not present in the system!\n"); + return (0); +} + +__sym_compat(des_setkey, __freebsd11_des_setkey, FBSD_1.0); +__sym_compat(des_cipher, __freebsd11_des_cipher, FBSD_1.0); +__sym_compat(setkey, __freebsd11_setkey, FBSD_1.0); +__sym_compat(encrypt, __freebsd11_encrypt, FBSD_1.0); diff --git a/lib/libc/gen/ctermid.3 b/lib/libc/gen/ctermid.3 new file mode 100644 index 000000000000..2a53412f1b29 --- /dev/null +++ b/lib/libc/gen/ctermid.3 @@ -0,0 +1,105 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 1, 2011 +.Dt CTERMID 3 +.Os +.Sh NAME +.Nm ctermid +.Nd generate terminal pathname +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdio.h +.Ft char * +.Fn ctermid "char *buf" +.Ft char * +.Fn ctermid_r "char *buf" +.Sh DESCRIPTION +The +.Fn ctermid +function generates a string, that, when used as a pathname, refers to +the current controlling terminal of the calling process. +.Pp +If +.Fa buf +is the +.Dv NULL +pointer, a pointer to a static area is returned. +Otherwise, the pathname is copied into the memory referenced by +.Fa buf . +The argument +.Fa buf +is assumed to be at least +.Dv L_ctermid +(as defined in the include +file +.In stdio.h ) +bytes long. +.Pp +The +.Fn ctermid_r +function +provides the same functionality as +.Fn ctermid +except that if +.Fa buf +is a +.Dv NULL +pointer, +.Dv NULL +is returned. +.Pp +If no suitable lookup of the controlling terminal name can be performed, +this implementation returns +.Ql /dev/tty . +.Sh RETURN VALUES +Upon successful completion, a +.Pf non- Dv NULL +pointer is returned. +Otherwise, a +.Dv NULL +pointer is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +The current implementation detects no error conditions. +.Sh SEE ALSO +.Xr ttyname 3 +.Sh STANDARDS +The +.Fn ctermid +function conforms to +.St -p1003.1-88 . +.Sh BUGS +By default the +.Fn ctermid +function +writes all information to an internal static object. +Subsequent calls to +.Fn ctermid +will modify the same object. diff --git a/lib/libc/gen/ctermid.c b/lib/libc/gen/ctermid.c new file mode 100644 index 000000000000..fb117b3c8ded --- /dev/null +++ b/lib/libc/gen/ctermid.c @@ -0,0 +1,70 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2011 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/sysctl.h> + +#include <errno.h> +#include <paths.h> +#include <stdio.h> +#include <string.h> +#include <ssp/ssp.h> + +#define LEN_PATH_DEV (sizeof(_PATH_DEV) - 1) + +char * +__ssp_real(ctermid)(char *s) +{ + static char def[sizeof(_PATH_DEV) + SPECNAMELEN]; + struct stat sb; + size_t dlen; + int sverrno; + + if (s == NULL) { + s = def; + dlen = sizeof(def) - LEN_PATH_DEV; + } else + dlen = L_ctermid - LEN_PATH_DEV; + strcpy(s, _PATH_TTY); + + /* Attempt to perform a lookup of the actual TTY pathname. */ + sverrno = errno; + if (stat(_PATH_TTY, &sb) == 0 && S_ISCHR(sb.st_mode)) + (void)sysctlbyname("kern.devname", s + LEN_PATH_DEV, + &dlen, &sb.st_rdev, sizeof(sb.st_rdev)); + errno = sverrno; + return (s); +} + +char * +__ssp_real(ctermid_r)(char *s) +{ + + return (s != NULL ? ctermid(s) : NULL); +} diff --git a/lib/libc/gen/daemon.3 b/lib/libc/gen/daemon.3 new file mode 100644 index 000000000000..4619ba3489aa --- /dev/null +++ b/lib/libc/gen/daemon.3 @@ -0,0 +1,139 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd February 27, 2023 +.Dt DAEMON 3 +.Os +.Sh NAME +.Nm daemon +.Nd run in the background +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn daemon "int nochdir" "int noclose" +.Ft int +.Fn daemonfd "int chdirfd" "int nullfd" +.Sh DESCRIPTION +The +.Fn daemon +function is for programs wishing to detach themselves from the +controlling terminal and run in the background as system daemons. +.Pp +If the argument +.Fa nochdir +is zero, +.Fn daemon +changes the current working directory to the root +.Pq Pa / . +.Pp +If the argument +.Fa noclose +is zero, +.Fn daemon +redirects standard input, standard output, and standard error to +.Pa /dev/null . +.Pp +The +.Fn daemonfd +function is equivalent to the +.Fn daemon +function except that arguments are the descriptors for the current working +directory and to the descriptor to +.Pa /dev/null . +.Pp +If +.Fa chdirfd +is equal to +.Pq -1 +the current working directory is not changed. +.Pp +If +.Fa nullfd +is equals to +.Pq -1 +the redirection of standard input, standard output, and standard error is not +closed. +.Sh RETURN VALUES +.Rv -std daemon daemonfd +.Sh ERRORS +The +.Fn daemon +and +.Fn daemonfd +function may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr fork 2 +.Xr open 2 , +and +.Xr setsid 2 . +.Sh SEE ALSO +.Xr fork 2 , +.Xr setsid 2 , +.Xr sigaction 2 +.Sh HISTORY +The +.Fn daemon +function first appeared in +.Bx 4.4 . +The +.Fn daemonfd +function first appeared in +.Fx 12.0 . +.Sh CAVEATS +Unless the +.Fa noclose +argument is non-zero, +.Fn daemon +will close the first three file descriptors and redirect them to +.Pa /dev/null . +Normally, these correspond to standard input, standard output, and +standard error. +However, if any of those file descriptors refer to something else, they +will still be closed, resulting in incorrect behavior of the calling program. +This can happen if any of standard input, standard output, or standard +error have been closed before the program was run. +Programs using +.Fn daemon +should therefore either call +.Fn daemon +before opening any files or sockets, or verify that any file +descriptors obtained have values greater than 2. +.Pp +The +.Fn daemon +function temporarily ignores +.Dv SIGHUP +while calling +.Xr setsid 2 +to prevent a parent session group leader's calls to +.Xr fork 2 +and then +.Xr _exit 2 +from prematurely terminating the child process. diff --git a/lib/libc/gen/daemon.c b/lib/libc/gen/daemon.c new file mode 100644 index 000000000000..525c99761aa3 --- /dev/null +++ b/lib/libc/gen/daemon.c @@ -0,0 +1,115 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 The Regents of the University of California. + * Copyright (c) 2017 Mariusz Zaborski <oshogbo@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <stdlib.h> +#include <signal.h> +#include <unistd.h> +#include "un-namespace.h" +#include "libc_private.h" + +int +daemonfd(int chdirfd, int nullfd) +{ + struct sigaction osa, sa; + pid_t newgrp; + int oerrno; + int osa_ok; + + /* A SIGHUP may be thrown when the parent exits below. */ + sigemptyset(&sa.sa_mask); + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + osa_ok = __libc_sigaction(SIGHUP, &sa, &osa); + + switch (fork()) { + case -1: + return (-1); + case 0: + break; + default: + /* + * A fine point: _exit(0), not exit(0), to avoid triggering + * atexit(3) processing + */ + _exit(0); + } + + newgrp = setsid(); + oerrno = errno; + if (osa_ok != -1) + __libc_sigaction(SIGHUP, &osa, NULL); + + if (newgrp == -1) { + errno = oerrno; + return (-1); + } + + if (chdirfd != -1) + (void)fchdir(chdirfd); + + if (nullfd != -1) { + (void)_dup2(nullfd, STDIN_FILENO); + (void)_dup2(nullfd, STDOUT_FILENO); + (void)_dup2(nullfd, STDERR_FILENO); + } + return (0); +} + +int +daemon(int nochdir, int noclose) +{ + int chdirfd, nullfd, ret; + + if (!noclose) + nullfd = _open(_PATH_DEVNULL, O_RDWR, 0); + else + nullfd = -1; + + if (!nochdir) + chdirfd = _open("/", O_EXEC); + else + chdirfd = -1; + + ret = daemonfd(chdirfd, nullfd); + + if (chdirfd != -1) + _close(chdirfd); + + if (nullfd > 2) + _close(nullfd); + + return (ret); +} diff --git a/lib/libc/gen/devname-compat11.c b/lib/libc/gen/devname-compat11.c new file mode 100644 index 000000000000..b01b0845e261 --- /dev/null +++ b/lib/libc/gen/devname-compat11.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <stdlib.h> +#include "gen-compat.h" + +char * +freebsd11_devname(uint32_t dev, mode_t type) +{ + + return (devname(dev, type)); +} + +char * +freebsd11_devname_r(uint32_t dev, mode_t type, char *buf, int len) +{ + + return (devname_r(dev, type, buf, len)); +} + +__sym_compat(devname, freebsd11_devname, FBSD_1.0); +__sym_compat(devname_r, freebsd11_devname_r, FBSD_1.0); diff --git a/lib/libc/gen/devname.3 b/lib/libc/gen/devname.3 new file mode 100644 index 000000000000..44c1ff951cfa --- /dev/null +++ b/lib/libc/gen/devname.3 @@ -0,0 +1,112 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd February 22, 2005 +.Dt DEVNAME 3 +.Os +.Sh NAME +.Nm devname +.Nd "get device name" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/stat.h +.In stdlib.h +.Ft char * +.Fn devname "dev_t dev" "mode_t type" +.Ft char * +.Fn devname_r "dev_t dev" "mode_t type" "char *buf" "int len" +.Ft char * +.Fn fdevname "int fd" +.Ft char * +.Fn fdevname_r "int fd" "char *buf" "int len" +.Sh DESCRIPTION +The +.Fn devname +function returns a pointer to the name of the block or character +device in +.Pa /dev +with a device number of +.Fa dev , +and a file type matching the one encoded in +.Fa type +which must be one of +.Dv S_IFBLK +or +.Dv S_IFCHR . +To find the right name, +.Fn devname +asks the kernel via the +.Va kern.devname +sysctl. +If it is unable to come up with a suitable name, +it will format the information encapsulated in +.Fa dev +and +.Fa type +in a human-readable format. +.Pp +The +.Fn fdevname +and +.Fn fdevname_r +function obtains the device name directly from a file descriptor +pointing to a character device. +If it is unable to come up with a suitable name, these functions will +return a NULL pointer. +.Pp +.Fn devname +and +.Fn fdevname +return the name stored in a static buffer which will be overwritten +on subsequent calls. +.Fn devname_r +and +.Fn fdevname_r +take a buffer and length as argument to avoid this problem. +.Sh EXAMPLES +.Bd -literal -compact +int fd; +struct stat buf; +char *name; + + fd = open("/dev/tun"); + fstat(fd, &buf); + printf("devname is /dev/%s\en", devname(buf.st_rdev, S_IFCHR)); + printf("fdevname is /dev/%s\en", fdevname(fd)); +.Ed +.Sh SEE ALSO +.Xr stat 2 +.Sh HISTORY +The +.Fn devname +function appeared in +.Bx 4.4 . +The +.Fn fdevname +function appeared in +.Fx 8.0 . diff --git a/lib/libc/gen/devname.c b/lib/libc/gen/devname.c new file mode 100644 index 000000000000..ebb56132c48d --- /dev/null +++ b/lib/libc/gen/devname.c @@ -0,0 +1,71 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <stdio.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> + +char * +devname_r(dev_t dev, mode_t type, char *buf, int len) +{ + int i; + size_t j; + + if (dev == NODEV || !(S_ISCHR(type) || S_ISBLK(type))) { + strlcpy(buf, "#NODEV", len); + return (buf); + } + + if (S_ISCHR(type)) { + j = len; + i = sysctlbyname("kern.devname", buf, &j, &dev, sizeof (dev)); + if (i == 0) + return (buf); + } + + /* Finally just format it */ + snprintf(buf, len, "#%c:%#jx", + S_ISCHR(type) ? 'C' : 'B', (uintmax_t)dev); + return (buf); +} + +char * +devname(dev_t dev, mode_t type) +{ + static char buf[SPECNAMELEN + 1]; + + return (devname_r(dev, type, buf, sizeof(buf))); +} diff --git a/lib/libc/gen/directory.3 b/lib/libc/gen/directory.3 new file mode 100644 index 000000000000..263dfdd6eb95 --- /dev/null +++ b/lib/libc/gen/directory.3 @@ -0,0 +1,400 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd August 1, 2020 +.Dt DIRECTORY 3 +.Os +.Sh NAME +.Nm opendir , +.Nm fdopendir , +.Nm readdir , +.Nm readdir_r , +.Nm telldir , +.Nm seekdir , +.Nm rewinddir , +.Nm closedir , +.Nm fdclosedir , +.Nm dirfd +.Nd directory operations +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In dirent.h +.Ft DIR * +.Fn opendir "const char *filename" +.Ft DIR * +.Fn fdopendir "int fd" +.Ft struct dirent * +.Fn readdir "DIR *dirp" +.Ft int +.Fn readdir_r "DIR *dirp" "struct dirent *entry" "struct dirent **result" +.Ft long +.Fn telldir "DIR *dirp" +.Ft void +.Fn seekdir "DIR *dirp" "long loc" +.Ft void +.Fn rewinddir "DIR *dirp" +.Ft int +.Fn closedir "DIR *dirp" +.Ft int +.Fn fdclosedir "DIR *dirp" +.Ft int +.Fn dirfd "DIR *dirp" +.Sh DESCRIPTION +.Bf -symbolic +The +.Fn readdir_r +interface is deprecated +because it cannot be used correctly unless +.Brq Va NAME_MAX +is a fixed value. +.Ef +.Pp +The +.Fn opendir +function +opens the directory named by +.Fa filename , +associates a +.Em directory stream +with it +and +returns a pointer to be used to identify the +.Em directory stream +in subsequent operations. +The pointer +.Dv NULL +is returned if +.Fa filename +cannot be accessed, or if it cannot +.Xr malloc 3 +enough memory to hold the whole thing. +.Pp +The +.Fn fdopendir +function is equivalent to the +.Fn opendir +function except that the directory is specified by a file descriptor +.Fa fd +rather than by a name. +The file offset associated with the file descriptor at the time of the call +determines which entries are returned. +.Pp +Upon successful return from +.Fn fdopendir , +the file descriptor is under the control of the system, +and if any attempt is made to close the file descriptor, +or to modify the state of the associated description other than by means +of +.Fn closedir , +.Fn readdir , +.Fn readdir_r , +or +.Fn rewinddir , +the behavior is undefined. +Upon calling +.Fn closedir +the file descriptor is closed. +The +.Dv FD_CLOEXEC +flag is set on the file descriptor by a successful call to +.Fn fdopendir . +.Pp +The +.Fn readdir +function +returns a pointer to the next directory entry. +The directory entry remains valid until the next call to +.Fn readdir +or +.Fn closedir +on the same +.Em directory stream . +The function returns +.Dv NULL +upon reaching the end of the directory or on error. +In the event of an error, +.Va errno +may be set to any of the values documented for the +.Xr getdirentries 2 +system call. +.Pp +The +.Fn readdir_r +function +provides the same functionality as +.Fn readdir , +but the caller must provide a directory +.Fa entry +buffer to store the results in. +The buffer must be large enough for a +.Vt struct dirent +with a +.Va d_name +array with +.Brq Va NAME_MAX ++ 1 elements. +If the read succeeds, +.Fa result +is pointed at the +.Fa entry ; +upon reaching the end of the directory +.Fa result +is set to +.Dv NULL . +The +.Fn readdir_r +function +returns 0 on success or an error number to indicate failure. +.Pp +The +.Fn telldir +function +returns a token representing the current location associated with the named +.Em directory stream . +Values returned by +.Fn telldir +are good only for the lifetime of the +.Dv DIR +pointer, +.Fa dirp , +from which they are derived. +If the directory is closed and then +reopened, prior values returned by +.Fn telldir +will no longer be valid. +Values returned by +.Fn telldir +are also invalidated by a call to +.Fn rewinddir . +.Pp +The +.Fn seekdir +function +sets the position of the next +.Fn readdir +operation on the +.Em directory stream . +The new position reverts to the one associated with the +.Em directory stream +when the +.Fn telldir +operation was performed. +.Pp +The +.Fn rewinddir +function +resets the position of the named +.Em directory stream +to the beginning of the directory. +.Pp +The +.Fn closedir +function +closes the named +.Em directory stream +and frees the structure associated with the +.Fa dirp +pointer, +returning 0 on success. +On failure, \-1 is returned and the global variable +.Va errno +is set to indicate the error. +.Pp +The +.Fn fdclosedir +function is equivalent to the +.Fn closedir +function except that this function returns directory file descriptor instead of +closing it. +.Pp +The +.Fn dirfd +function +returns the integer file descriptor associated with the named +.Em directory stream , +see +.Xr open 2 . +.Sh EXAMPLES +Sample code which searches a directory for entry ``name'' is: +.Bd -literal -offset indent +dirp = opendir("."); +if (dirp == NULL) + return (ERROR); +len = strlen(name); +while ((dp = readdir(dirp)) != NULL) { + if (dp->d_namlen == len && strcmp(dp->d_name, name) == 0) { + (void)closedir(dirp); + return (FOUND); + } +} +(void)closedir(dirp); +return (NOT_FOUND); +.Ed +.Sh ERRORS +The +.Fn opendir +function will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +Search permission is denied for the component of the path prefix of +.Fa filename +or read permission is denied for +.Fa filename . +.It Bq Er ELOOP +A loop exists in symbolic links encountered during resolution of the +.Fa filename +argument. +.It Bq Er ENAMETOOLONG +The length of the +.Fa filename +argument exceeds +.Brq Dv PATH_MAX +or +a pathname component is longer than +.Brq Dv NAME_MAX . +.It Bq Er ENOENT +A component of +.Fa filename +does not name an existing directory or +.Fa filename +is an empty string. +.It Bq Er ENOTDIR +A component of +.Fa filename +is not a directory. +.El +.Pp +The +.Fn fdopendir +function will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid file descriptor open for reading. +.It Bq Er ENOTDIR +The descriptor +.Fa fd +is not associated with a directory. +.El +.Pp +The +.Fn readdir +and +.Fn readdir_r +functions may also fail and set +.Va errno +for any of the errors specified for the routine +.Xr getdents 2 . +.Pp +The +.Fn telldir +function may also fail and set +.Va errno +for any of the errors specified for the routine +.Xr realloc 3 . +.Pp +The +.Fn closedir +function may also fail and set +.Va errno +for any of the errors specified for the routine +.Xr close 2 . +.Sh SEE ALSO +.Xr close 2 , +.Xr lseek 2 , +.Xr open 2 , +.Xr read 2 , +.Xr dir 5 +.Sh STANDARDS +The +.Fn closedir , +.Fn dirfd , +.Fn fdopendir , +.Fn opendir , +.Fn readdir , +.Fn readdir_r , +.Fn rewinddir , +.Fn seekdir +and +.Fn telldir +functions are expected to conform to +.St -p1003.1-2008 . +The +.Fn fdclosedir +function and the +.Fa d_off , +.Fa d_reclen +and +.Fa d_type +fields of +.Vt struct dirent +are non-standard, and should not be used in portable programs. +.Sh HISTORY +The +.Fn opendir , +.Fn readdir , +.Fn telldir , +.Fn seekdir , +.Fn rewinddir , +.Fn closedir , +and +.Fn dirfd +functions appeared in +.Bx 4.2 . +The +.Fn fdopendir +function appeared in +.Fx 8.0 . +.Fn fdclosedir +function appeared in +.Fx 10.0 . +.Sh BUGS +The behaviour of +.Fn telldir +and +.Fn seekdir +is likely to be wrong if there are parallel unlinks happening +and the directory is larger than one page. +There is code to ensure that a +.Fn seekdir +to the location given by a +.Fn telldir +immediately before the last +.Fn readdir +will always set the correct location to return the same value as that last +.Fn readdir +performed. +This is enough for some applications which want to +"push back the last entry read", e.g., Samba. +Seeks back to any other location, +other than the beginning of the directory, +may result in unexpected behaviour if deletes are present. +It is hoped that this situation will be resolved with changes to +.Fn getdirentries +and the VFS. diff --git a/lib/libc/gen/dirfd.c b/lib/libc/gen/dirfd.c new file mode 100644 index 000000000000..85090bd4da6c --- /dev/null +++ b/lib/libc/gen/dirfd.c @@ -0,0 +1,42 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2011 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> + +#include <dirent.h> +#include "un-namespace.h" + +#include "gen-private.h" + +int +dirfd(DIR *dirp) +{ + + return (_dirfd(dirp)); +} diff --git a/lib/libc/gen/dirname.3 b/lib/libc/gen/dirname.3 new file mode 100644 index 000000000000..bb3be09ab4c4 --- /dev/null +++ b/lib/libc/gen/dirname.3 @@ -0,0 +1,83 @@ +.\" $OpenBSD: dirname.3,v 1.17 2007/05/31 19:19:28 jmc Exp $ +.\" +.\" Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd September 5, 2016 +.Dt DIRNAME 3 +.Os +.Sh NAME +.Nm dirname +.Nd extract the directory part of a pathname +.Sh SYNOPSIS +.In libgen.h +.Ft char * +.Fn dirname "char *path" +.Sh DESCRIPTION +The +.Fn dirname +function is the converse of +.Xr basename 3 ; +it returns a pointer to the parent directory of the pathname pointed to by +.Fa path . +Any trailing +.Sq \&/ +characters are not counted as part of the directory +name. +.Sh IMPLEMENTATION NOTES +This implementation of +.Fn dirname +uses the buffer provided by the caller to store the resulting parent +directory. +Other vendor implementations may return a pointer to internal storage +space instead. +The advantage of the former approach is that it ensures thread-safety, +while also placing no upper limit on the supported length of the +pathname. +.Sh RETURN VALUES +If +.Fa path +is a null pointer, the empty string, or contains no +.Sq \&/ +characters, +.Fn dirname +returns a pointer to the string +.Qq \&. , +signifying the current directory. +Otherwise, +it returns a pointer to the parent directory of +.Fa path . +.Sh SEE ALSO +.Xr basename 1 , +.Xr dirname 1 , +.Xr basename 3 +.Sh STANDARDS +The +.Fn dirname +function conforms to +.St -xpg4.2 . +.Sh HISTORY +The +.Fn dirname +function first appeared in +.Ox 2.2 +and +.Fx 4.2 . +.Pp +In +.Fx 12.0 , +this function was reimplemented to store its result in the provided +input buffer. +.Sh AUTHORS +.An Nuxi, the Netherlands diff --git a/lib/libc/gen/dirname.c b/lib/libc/gen/dirname.c new file mode 100644 index 000000000000..7157fec23630 --- /dev/null +++ b/lib/libc/gen/dirname.c @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2015-2016 Nuxi, https://nuxi.nl/ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <libgen.h> +#include <string.h> + +char * +(dirname)(char *path) +{ + char *end; + + /* + * If path is a null pointer or points to an empty string, + * dirname() shall return a pointer to the string ".". + */ + if (path == NULL || *path == '\0') + return (__DECONST(char *, ".")); + + /* Find end of last pathname component. */ + end = path + strlen(path); + while (end > path + 1 && *(end - 1) == '/') + --end; + + /* Strip off the last pathname component. */ + while (end > path && *(end - 1) != '/') + --end; + + /* + * If path does not contain a '/', then dirname() shall return a + * pointer to the string ".". + */ + if (end == path) { + path[0] = '.'; + path[1] = '\0'; + return (path); + } + + /* + * Remove trailing slashes from the resulting directory name. Ensure + * that at least one character remains. + */ + while (end > path + 1 && *(end - 1) == '/') + --end; + + /* Null terminate directory name and return it. */ + *end = '\0'; + return (path); +} diff --git a/lib/libc/gen/dirname_compat.c b/lib/libc/gen/dirname_compat.c new file mode 100644 index 000000000000..7eca7eb03f83 --- /dev/null +++ b/lib/libc/gen/dirname_compat.c @@ -0,0 +1,78 @@ +/* $OpenBSD: dirname.c,v 1.13 2005/08/08 08:05:33 espie Exp $ */ + +/* + * Copyright (c) 1997, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <errno.h> +#include <libgen.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> + +char * __freebsd11_dirname(char *path); + +char * +__freebsd11_dirname(char *path) +{ + static char *dname = NULL; + size_t len; + const char *endp; + + if (dname == NULL) { + dname = (char *)malloc(MAXPATHLEN); + if (dname == NULL) + return(NULL); + } + + /* Empty or NULL string gets treated as "." */ + if (path == NULL || *path == '\0') { + dname[0] = '.'; + dname[1] = '\0'; + return (dname); + } + + /* Strip any trailing slashes */ + endp = path + strlen(path) - 1; + while (endp > path && *endp == '/') + endp--; + + /* Find the start of the dir */ + while (endp > path && *endp != '/') + endp--; + + /* Either the dir is "/" or there are no slashes */ + if (endp == path) { + dname[0] = *endp == '/' ? '/' : '.'; + dname[1] = '\0'; + return (dname); + } else { + /* Move forward past the separating slashes */ + do { + endp--; + } while (endp > path && *endp == '/'); + } + + len = endp - path + 1; + if (len >= MAXPATHLEN) { + errno = ENAMETOOLONG; + return (NULL); + } + memcpy(dname, path, len); + dname[len] = '\0'; + return (dname); +} + +__sym_compat(dirname, __freebsd11_dirname, FBSD_1.0); diff --git a/lib/libc/gen/disklabel.c b/lib/libc/gen/disklabel.c new file mode 100644 index 000000000000..4b3730920529 --- /dev/null +++ b/lib/libc/gen/disklabel.c @@ -0,0 +1,162 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#define DKTYPENAMES +#define FSTYPENAMES +#include <sys/disklabel.h> + +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ctype.h> + +static int +gettype(char *t, const char **names) +{ + const char **nm; + + for (nm = names; *nm; nm++) + if (strcasecmp(t, *nm) == 0) + return (nm - names); + if (isdigit((unsigned char)*t)) + return (atoi(t)); + return (0); +} + +struct disklabel * +getdiskbyname(const char *name) +{ + static struct disklabel disk; + struct disklabel *dp = &disk; + struct partition *pp; + char *buf; + char *db_array[2] = { _PATH_DISKTAB, 0 }; + char *cp, *cq; /* can't be register */ + char p, max, psize[3], pbsize[3], + pfsize[3], poffset[3], ptype[3]; + u_int32_t *dx; + + if (cgetent(&buf, db_array, (char *) name) < 0) + return NULL; + + bzero((char *)&disk, sizeof(disk)); + /* + * typename + */ + cq = dp->d_typename; + cp = buf; + while (cq < dp->d_typename + sizeof(dp->d_typename) - 1 && + (*cq = *cp) && *cq != '|' && *cq != ':') + cq++, cp++; + *cq = '\0'; + + if (cgetstr(buf, "ty", &cq) > 0) { + if (strcmp(cq, "removable") == 0) + dp->d_flags |= D_REMOVABLE; + else if (cq && strcmp(cq, "simulated") == 0) + dp->d_flags |= D_RAMDISK; + free(cq); + } + if (cgetcap(buf, "sf", ':') != NULL) + dp->d_flags |= D_BADSECT; + +#define getnumdflt(field, dname, dflt) \ + { long f; (field) = (cgetnum(buf, dname, &f) == -1) ? (dflt) : f; } + + getnumdflt(dp->d_secsize, "se", DEV_BSIZE); + getnumdflt(dp->d_ntracks, "nt", 0); + getnumdflt(dp->d_nsectors, "ns", 0); + getnumdflt(dp->d_ncylinders, "nc", 0); + + if (cgetstr(buf, "dt", &cq) > 0) { + dp->d_type = gettype(cq, dktypenames); + free(cq); + } else + getnumdflt(dp->d_type, "dt", 0); + getnumdflt(dp->d_secpercyl, "sc", dp->d_nsectors * dp->d_ntracks); + getnumdflt(dp->d_secperunit, "su", dp->d_secpercyl * dp->d_ncylinders); + getnumdflt(dp->d_rpm, "rm", 3600); + getnumdflt(dp->d_interleave, "il", 1); + getnumdflt(dp->d_trackskew, "sk", 0); + getnumdflt(dp->d_cylskew, "cs", 0); + getnumdflt(dp->d_headswitch, "hs", 0); + getnumdflt(dp->d_trkseek, "ts", 0); + getnumdflt(dp->d_bbsize, "bs", BBSIZE); + getnumdflt(dp->d_sbsize, "sb", 0); + strcpy(psize, "px"); + strcpy(pbsize, "bx"); + strcpy(pfsize, "fx"); + strcpy(poffset, "ox"); + strcpy(ptype, "tx"); + max = 'a' - 1; + pp = &dp->d_partitions[0]; + for (p = 'a'; p < 'a' + MAXPARTITIONS; p++, pp++) { + long l; + psize[1] = pbsize[1] = pfsize[1] = poffset[1] = ptype[1] = p; + if (cgetnum(buf, psize, &l) == -1) + pp->p_size = 0; + else { + pp->p_size = l; + cgetnum(buf, poffset, &l); + pp->p_offset = l; + getnumdflt(pp->p_fsize, pfsize, 0); + if (pp->p_fsize) { + long bsize; + + if (cgetnum(buf, pbsize, &bsize) == 0) + pp->p_frag = bsize / pp->p_fsize; + else + pp->p_frag = 8; + } + getnumdflt(pp->p_fstype, ptype, 0); + if (pp->p_fstype == 0) + if (cgetstr(buf, ptype, &cq) >= 0) { + pp->p_fstype = gettype(cq, fstypenames); + free(cq); + } + max = p; + } + } + dp->d_npartitions = max + 1 - 'a'; + (void)strcpy(psize, "dx"); + dx = dp->d_drivedata; + for (p = '0'; p < '0' + NDDATA; p++, dx++) { + psize[1] = p; + getnumdflt(*dx, psize, 0); + } + dp->d_magic = DISKMAGIC; + dp->d_magic2 = DISKMAGIC; + free(buf); + return (dp); +} diff --git a/lib/libc/gen/dl_iterate_phdr.3 b/lib/libc/gen/dl_iterate_phdr.3 new file mode 100644 index 000000000000..448d6fbb2fc5 --- /dev/null +++ b/lib/libc/gen/dl_iterate_phdr.3 @@ -0,0 +1,117 @@ +.\" Copyright (c) 2005 Mark Kettenis +.\" Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" $OpenBSD: dl_iterate_phdr.3,v 1.3 2007/05/31 19:19:48 jmc Exp $ +.Dd April 5, 2021 +.Dt DL_ITERATE_PHDR 3 +.Os +.Sh NAME +.Nm dl_iterate_phdr +.Nd iterate over program headers +.Sh LIBRARY +For the dynamically linked binaries, the service is provided by +.Xr ld-elf.so.1 1 +dynamic linker. +Statically linked programs use an implementation of +.Fn dl_iterate_phdr +from libc. +.Sh SYNOPSIS +.In link.h +.Ft int +.Fn dl_iterate_phdr "int (*callback)(struct dl_phdr_info *, size_t, void *)" "void *data" +.Sh DESCRIPTION +The +.Fn dl_iterate_phdr +function iterates over all ELF objects loaded into a process's +address space, calling +.Fa callback +for each object, passing it information about the object's +program headers and the +.Fa data +argument. +The iteration is aborted when all objects are passed, or when the next +.Fa callback +call returns non-zero value. +The information about the program headers is passed in a structure +that is defined as: +.Bd -literal +struct dl_phdr_info { + Elf_Addr dlpi_addr; + const char *dlpi_name; + const Elf_Phdr *dlpi_phdr; + Elf_Half dlpi_phnum; + unsigned long long int dlpi_adds; + unsigned long long int dlpi_subs; + size_t dlpi_tls_modid; + void *dlpi_tls_data; +}; +.Ed +.Pp +The members of +.Li struct dl_phdr_info +have the following meaning: +.Bl -tag -width dlpi_tls_modid +.It Fa dlpi_addr +The base address at which the object is mapped into the address +space of the calling process. +.It Fa dlpi_name +The pathname of the ELF object. +.It Fa dlpi_phdr +A pointer to the object's program headers. +.It Fa dlpi_phnum +The number of program headers in the object. +.It Fa dlpi_adds +The counter of the object loads performed by the dynamic linker. +.It Fa dlpi_subs +The counter of the object unloads performed by the dynamic linker. +.It Fa dlpi_tls_modid +The TLS index of the object. +.It Fa dlpi_tls_data +A pointer to the calling thread' TLS data segment for this module, +if it was allocated, +.Dv NULL +otherwise. +.El +.Pp +Future versions of +.Fx +might add more members to this structure. +To make it possible for programs to check whether any new members have +been added, the size of the structure is passed as an second argument to +.Fa callback . +.Pp +The third argument to callback is the +.Fa data +value passed to the call to +.Fn dl_iterate_phdr , +allowing the +.Fa callback +to have a context. +.Sh RETURN VALUES +The +.Fn dl_iterate_phdr +returns the value returned by the last +.Fa callback +call executed. +.Sh SEE ALSO +.Xr ld 1 , +.Xr ld-elf.so.1 1 , +.Xr dlopen 3 , +.Xr elf 5 +.Sh HISTORY +The +.Nm +function first appeared in +.Fx 7.0 . diff --git a/lib/libc/gen/dladdr.3 b/lib/libc/gen/dladdr.3 new file mode 100644 index 000000000000..a9abf95393c3 --- /dev/null +++ b/lib/libc/gen/dladdr.3 @@ -0,0 +1,131 @@ +.\" +.\" Copyright (c) 1998 John D. Polstra +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd February 5, 1998 +.Dt DLADDR 3 +.Os +.Sh NAME +.Nm dladdr +.Nd find the shared object containing a given address +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In dlfcn.h +.Ft int +.Fn dladdr "const void *addr" "Dl_info *info" +.Sh DESCRIPTION +The +.Fn dladdr +function +queries the dynamic linker for information about the shared object +containing the address +.Fa addr . +The information is returned in the structure specified by +.Fa info . +The structure contains at least the following members: +.Bl -tag -width "XXXconst char *dli_fname" +.It Li "const char *dli_fname" +The pathname of the shared object containing the address. +.It Li "void *dli_fbase" +The base address at which the shared object is mapped into the +address space of the calling process. +.It Li "const char *dli_sname" +The name of the nearest run-time symbol with a value less than or +equal to +.Fa addr . +When possible, the symbol name is returned as it would appear in C +source code. +.Pp +If no symbol with a suitable value is found, both this field and +.Va dli_saddr +are set to +.Dv NULL . +.It Li "void *dli_saddr" +The value of the symbol returned in +.Li dli_sname . +.El +.Pp +The +.Fn dladdr +function +is available only in dynamically linked programs. +.Sh ERRORS +If a mapped shared object containing +.Fa addr +cannot be found, +.Fn dladdr +returns 0. +In that case, a message detailing the failure can be retrieved by +calling +.Fn dlerror . +.Pp +On success, a non-zero value is returned. +.Sh SEE ALSO +.Xr rtld 1 , +.Xr dlopen 3 +.Sh HISTORY +The +.Fn dladdr +function first appeared in the Solaris operating system. +.Sh BUGS +This implementation is bug-compatible with the Solaris +implementation. +In particular, the following bugs are present: +.Bl -bullet +.It +If +.Fa addr +lies in the main executable rather than in a shared library, the +pathname returned in +.Va dli_fname +may not be correct. +The pathname is taken directly from +.Va argv[0] +of the calling process. +When executing a program specified by its +full pathname, most shells set +.Va argv[0] +to the pathname. +But this is not required of shells or guaranteed +by the operating system. +.It +If +.Fa addr +is of the form +.Va &func , +where +.Va func +is a global function, its value may be an unpleasant surprise. +In +dynamically linked programs, the address of a global function is +considered to point to its program linkage table entry, rather than to +the entry point of the function itself. +This causes most global +functions to appear to be defined within the main executable, rather +than in the shared libraries where the actual code resides. +.It +Returning 0 as an indication of failure goes against long-standing +Unix tradition. +.El diff --git a/lib/libc/gen/dlfcn.c b/lib/libc/gen/dlfcn.c new file mode 100644 index 000000000000..ae1c8d83df19 --- /dev/null +++ b/lib/libc/gen/dlfcn.c @@ -0,0 +1,375 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1998 John D. Polstra + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#if !defined(IN_LIBDL) || defined(PIC) + +/* + * Linkage to services provided by the dynamic linker. + */ +#include <sys/types.h> +#include <sys/mman.h> +#include <machine/atomic.h> +#include <dlfcn.h> +#include <errno.h> +#include <link.h> +#include <stddef.h> +#include <string.h> +#include "namespace.h" +#include <pthread.h> +#include "un-namespace.h" +#include "rtld.h" +#include "libc_private.h" +#include "reentrant.h" + +static const char sorry[] = "Service unavailable"; + +void _rtld_thread_init(void *); +void _rtld_atfork_pre(int *); +void _rtld_atfork_post(int *); + +/* + * For ELF, the dynamic linker directly resolves references to its + * services to functions inside the dynamic linker itself. These + * weak-symbol stubs are necessary so that "ld" won't complain about + * undefined symbols. The stubs are executed only when the program is + * linked statically, or when a given service isn't implemented in the + * dynamic linker. They must return an error if called, and they must + * be weak symbols so that the dynamic linker can override them. + */ + +#pragma weak _rtld_error +void +_rtld_error(const char *fmt __unused, ...) +{ +} + +#pragma weak dladdr +int +dladdr(const void *addr __unused, Dl_info *dlip __unused) +{ + + _rtld_error(sorry); + return (0); +} + +#pragma weak dlclose +int +dlclose(void *handle __unused) +{ + + _rtld_error(sorry); + return (-1); +} + +#pragma weak dlerror +char * +dlerror(void) +{ + + return (__DECONST(char *, sorry)); +} + +#pragma weak dllockinit +void +dllockinit(void *context, + void *(*lock_create)(void *context) __unused, + void (*rlock_acquire)(void *lock) __unused, + void (*wlock_acquire)(void *lock) __unused, + void (*lock_release)(void *lock) __unused, + void (*lock_destroy)(void *lock) __unused, + void (*context_destroy)(void *context) __unused) +{ + + if (context_destroy != NULL) + context_destroy(context); +} + +#pragma weak dlopen +void * +dlopen(const char *name __unused, int mode __unused) +{ + + _rtld_error(sorry); + return (NULL); +} + +#pragma weak dlsym +void * +dlsym(void * __restrict handle __unused, const char * __restrict name __unused) +{ + + _rtld_error(sorry); + return (NULL); +} + +#pragma weak dlfunc +dlfunc_t +dlfunc(void * __restrict handle __unused, const char * __restrict name __unused) +{ + + _rtld_error(sorry); + return (NULL); +} + +#pragma weak dlvsym +void * +dlvsym(void * __restrict handle __unused, const char * __restrict name __unused, + const char * __restrict version __unused) +{ + + _rtld_error(sorry); + return (NULL); +} + +#pragma weak dlinfo +int +dlinfo(void * __restrict handle __unused, int request __unused, + void * __restrict p __unused) +{ + + _rtld_error(sorry); + return (0); +} + +#pragma weak _rtld_thread_init +void +_rtld_thread_init(void *li __unused) +{ + + _rtld_error(sorry); +} + +#ifndef IN_LIBDL +static pthread_once_t dl_phdr_info_once = PTHREAD_ONCE_INIT; +static struct dl_phdr_info phdr_info; +#ifndef PIC +static mutex_t dl_phdr_info_lock = MUTEX_INITIALIZER; +#endif + +static void +dl_init_phdr_info(void) +{ + Elf_Auxinfo *auxp; + unsigned int i; + + for (auxp = __elf_aux_vector; auxp->a_type != AT_NULL; auxp++) { + switch (auxp->a_type) { + case AT_BASE: + phdr_info.dlpi_addr = (Elf_Addr)auxp->a_un.a_ptr; + break; + case AT_EXECPATH: + phdr_info.dlpi_name = (const char *)auxp->a_un.a_ptr; + break; + case AT_PHDR: + phdr_info.dlpi_phdr = + (const Elf_Phdr *)auxp->a_un.a_ptr; + break; + case AT_PHNUM: + phdr_info.dlpi_phnum = (Elf_Half)auxp->a_un.a_val; + break; + } + } + for (i = 0; i < phdr_info.dlpi_phnum; i++) { + if (phdr_info.dlpi_phdr[i].p_type == PT_TLS) { + phdr_info.dlpi_tls_modid = 1; + } + } + phdr_info.dlpi_adds = 1; +} +#endif + +#pragma weak _dl_iterate_phdr_locked +int _dl_iterate_phdr_locked(int (*callback)(struct dl_phdr_info *, + size_t, void *), void *data); +int +_dl_iterate_phdr_locked( + int (*callback)(struct dl_phdr_info *, size_t, void *) __unused, + void *data __unused) +{ +#if defined IN_LIBDL + return (0); +#elif defined PIC + int (*r)(int (*)(struct dl_phdr_info *, size_t, void *), void *); + + r = dlsym(RTLD_DEFAULT, "dl_iterate_phdr"); + if (r == NULL) + return (0); + return (r(callback, data)); +#else + tls_index ti; + int ret; + + __init_elf_aux_vector(); + if (__elf_aux_vector == NULL) + return (1); + _once(&dl_phdr_info_once, dl_init_phdr_info); + ti.ti_module = 1; + ti.ti_offset = -TLS_DTV_OFFSET; + phdr_info.dlpi_tls_data = __tls_get_addr(&ti); + ret = callback(&phdr_info, sizeof(phdr_info), data); + return (ret); +#endif +} + +#pragma weak dl_iterate_phdr +int +dl_iterate_phdr(int (*callback)(struct dl_phdr_info *, size_t, void *) __unused, + void *data __unused) +{ + int error; + +#if !defined(IN_LIBDL) && !defined(PIC) + mutex_lock(&dl_phdr_info_lock); +#endif + error = _dl_iterate_phdr_locked(callback, data); +#if !defined(IN_LIBDL) && !defined(PIC) + mutex_unlock(&dl_phdr_info_lock); +#endif + return (error); +} + +#pragma weak fdlopen +void * +fdlopen(int fd __unused, int mode __unused) +{ + + _rtld_error(sorry); + return (NULL); +} + +#pragma weak _rtld_atfork_pre +void +_rtld_atfork_pre(int *locks __unused) +{ +} + +#pragma weak _rtld_atfork_post +void +_rtld_atfork_post(int *locks __unused) +{ +} + +#ifndef IN_LIBDL +struct _rtld_addr_phdr_cb_data { + const void *addr; + struct dl_phdr_info *dli; +}; + +static int +_rtld_addr_phdr_cb(struct dl_phdr_info *dli, size_t sz, void *arg) +{ + struct _rtld_addr_phdr_cb_data *rd; + const Elf_Phdr *ph; + unsigned i; + + rd = arg; + for (i = 0; i < dli->dlpi_phnum; i++) { + ph = &dli->dlpi_phdr[i]; + if (ph->p_type == PT_LOAD && + dli->dlpi_addr + ph->p_vaddr <= (uintptr_t)rd->addr && + (uintptr_t)rd->addr < dli->dlpi_addr + ph->p_vaddr + + ph->p_memsz) { + memcpy(rd->dli, dli, sz); + return (1); + } + } + return (0); +} +#endif + +#pragma weak _rtld_addr_phdr +int +_rtld_addr_phdr(const void *addr __unused, + struct dl_phdr_info *phdr_info_a __unused) +{ +#ifndef IN_LIBDL + struct _rtld_addr_phdr_cb_data rd; + + rd.addr = addr; + rd.dli = phdr_info_a; + return (dl_iterate_phdr(_rtld_addr_phdr_cb, &rd)); +#else + return (0); +#endif +} + +#pragma weak _rtld_get_stack_prot +int +_rtld_get_stack_prot(void) +{ +#ifndef IN_LIBDL + unsigned i; + int r; + static int ret; + + r = atomic_load_int(&ret); + if (r != 0) + return (r); + + _once(&dl_phdr_info_once, dl_init_phdr_info); + r = PROT_EXEC | PROT_READ | PROT_WRITE; + for (i = 0; i < phdr_info.dlpi_phnum; i++) { + if (phdr_info.dlpi_phdr[i].p_type != PT_GNU_STACK) + continue; + r = PROT_READ | PROT_WRITE; + if ((phdr_info.dlpi_phdr[i].p_flags & PF_X) != 0) + r |= PROT_EXEC; + break; + } + atomic_store_int(&ret, r); + return (r); +#else + return (0); +#endif +} + +#pragma weak _rtld_is_dlopened +int +_rtld_is_dlopened(void *arg __unused) +{ + + return (0); +} + +#pragma weak rtld_get_var +const char * +rtld_get_var(const char *name __unused) +{ + _rtld_error(sorry); + return (NULL); +} + +#pragma weak rtld_set_var +int +rtld_set_var(const char *name __unused, const char *val __unused) +{ + _rtld_error(sorry); + return (EINVAL); +} + +#endif /* !defined(IN_LIBDL) || defined(PIC) */ diff --git a/lib/libc/gen/dlinfo.3 b/lib/libc/gen/dlinfo.3 new file mode 100644 index 000000000000..8f30e5f10af1 --- /dev/null +++ b/lib/libc/gen/dlinfo.3 @@ -0,0 +1,288 @@ +.\" +.\" Copyright (c) 2003 Alexey Zelkin <phantom@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 21, 2020 +.Dt DLINFO 3 +.Os +.Sh NAME +.Nm dlinfo +.Nd information about dynamically loaded object +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In link.h +.In dlfcn.h +.Ft int +.Fn dlinfo "void * restrict handle" "int request" "void * restrict p" +.Sh DESCRIPTION +The +.Fn dlinfo +function provides information about dynamically loaded object. +The action taken by +.Fn dlinfo +and exact meaning and type of +.Fa p +argument depend on value of the +.Fa request +argument provided by caller. +.Pp +The +.Fa handle +argument is either the value returned from the +.Xr dlopen 3 +function call or special handle +.Dv RTLD_SELF . +If +.Fa handle +is the value returned from +.Xr dlopen 3 , +the information returned by the +.Fn dlinfo +function pertains to the specified object. +If handle is the special handle +.Dv RTLD_SELF , +the information returned pertains to the caller itself. +.Pp +Possible values for the +.Fa request +argument are: +.Bl -tag -width indent +.It Dv RTLD_DI_LINKMAP +Retrieve the +.Vt Link_map +.Pq Vt "struct link_map" +structure pointer for the specified +.Fa handle . +On successful return, the +.Fa p +argument is filled with the pointer to the +.Vt Link_map +structure +.Pq Fa "Link_map **p" +describing a shared object specified by the +.Fa handle +argument. +The +.Vt Link_map +structures are maintained as a doubly linked list by +.Xr ld.so 1 , +in the same order as +.Xr dlopen 3 +and +.Xr dlclose 3 +are called. +See +.Sx EXAMPLES , +example 1. +.Pp +The +.Vt Link_map +structure is defined in +.In link.h +and has the following members: +.Bd -literal -offset indent +caddr_t l_base; /* Base Address of library */ +const char *l_name; /* Absolute Path to Library */ +const void *l_ld; /* Pointer to .dynamic in memory */ +struct link_map *l_next, /* linked list of mapped libs */ + *l_prev; +caddr_t l_addr; /* Load Offset of library */ +const char *l_refname; /* Object this one filters for */ +.Ed +.Bl -tag -width ".Va l_addr" +.It Va l_base +The base address of the object loaded into memory. +.It Va l_name +The full name of the loaded shared object. +.It Va l_ld +The address of the dynamic linking information segment +.Pq Dv PT_DYNAMIC +loaded into memory. +.It Va l_next +The next +.Vt Link_map +structure on the link-map list. +.It Va l_prev +The previous +.Vt Link_map +structure on the link-map list. +.It Va l_addr +The load offset of the object, that is, the difference between +the actual load address and the base virtual address the object +was linked at. +.It Va l_refname +A name of the object this object filters for, if any. +If there are more then one filtee, a name from the first +.Dv DT_FILTER +dynamic entry is supplied. +.El +.It Dv RTLD_DI_SERINFO +Retrieve the library search paths associated with the given +.Fa handle +argument. +The +.Fa p +argument should point to +.Vt Dl_serinfo +structure buffer +.Pq Fa "Dl_serinfo *p" . +The +.Vt Dl_serinfo +structure must be initialized first with the +.Dv RTLD_DI_SERINFOSIZE +request. +.Pp +The returned +.Vt Dl_serinfo +structure contains +.Va dls_cnt +.Vt Dl_serpath +entries. +Each entry's +.Va dlp_name +field points to the search path. +The corresponding +.Va dlp_info +field contains one of more flags indicating the origin of the path (see the +.Dv LA_SER_* +flags defined in the +.In link.h +header file). +See +.Sx EXAMPLES , +example 2, for a usage example. +.It Dv RTLD_DI_SERINFOSIZE +Initialize a +.Vt Dl_serinfo +structure for use in a +.Dv RTLD_DI_SERINFO +request. +Both the +.Va dls_cnt +and +.Va dls_size +fields are returned to indicate the number of search paths applicable +to the handle, and the total size of a +.Vt Dl_serinfo +buffer required to hold +.Va dls_cnt +.Vt Dl_serpath +entries and the associated search path strings. +See +.Sx EXAMPLES , +example 2, for a usage example. +.It Va RTLD_DI_ORIGIN +Retrieve the origin of the dynamic object associated with the handle. +On successful return, +.Fa p +argument is filled with the +.Vt char +pointer +.Pq Fa "char *p" . +.El +.Sh RETURN VALUES +The +.Fn dlinfo +function returns 0 on success, or \-1 if an error occurred. +Whenever an error has been detected, a message detailing it can +be retrieved via a call to +.Xr dlerror 3 . +.Sh EXAMPLES +Example 1: Using +.Fn dlinfo +to retrieve +.Vt Link_map +structure. +.Pp +The following example shows how dynamic library can detect the list +of shared libraries loaded after caller's one. +For simplicity, error checking has been omitted. +.Bd -literal -offset indent +Link_map *map; + +dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map); + +while (map != NULL) { + printf("%p: %s\\n", map->l_addr, map->l_name); + map = map->l_next; +} +.Ed +.Pp +Example 2: Using +.Fn dlinfo +to retrieve the library search paths. +.Pp +The following example shows how a dynamic object can inspect the library +search paths that would be used to locate a simple filename with +.Xr dlopen 3 . +For simplicity, error checking has been omitted. +.Bd -literal -offset indent +Dl_serinfo _info, *info = &_info; +Dl_serpath *path; +unsigned int cnt; + +/* determine search path count and required buffer size */ +dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info); + +/* allocate new buffer and initialize */ +info = malloc(_info.dls_size); +info->dls_size = _info.dls_size; +info->dls_cnt = _info.dls_cnt; + +/* obtain sarch path information */ +dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info); + +path = &info->dls_serpath[0]; + +for (cnt = 1; cnt <= info->dls_cnt; cnt++, path++) { + (void) printf("%2d: %s\\n", cnt, path->dls_name); +} +.Ed +.Sh SEE ALSO +.Xr rtld 1 , +.Xr dladdr 3 , +.Xr dlopen 3 , +.Xr dlsym 3 +.Sh HISTORY +The +.Fn dlinfo +function first appeared in the Solaris operating system. +In +.Fx , +it first appeared in +.Fx 4.8 . +.Sh AUTHORS +.An -nosplit +The +.Fx +implementation of the +.Fn dlinfo +function was originally written by +.An Alexey Zelkin Aq Mt phantom@FreeBSD.org +and later extended and improved by +.An Alexander Kabaev Aq Mt kan@FreeBSD.org . +.Pp +The manual page for this function was written by +.An Alexey Zelkin Aq Mt phantom@FreeBSD.org . diff --git a/lib/libc/gen/dllockinit.3 b/lib/libc/gen/dllockinit.3 new file mode 100644 index 000000000000..8fe29f2516f9 --- /dev/null +++ b/lib/libc/gen/dllockinit.3 @@ -0,0 +1,125 @@ +.\" +.\" Copyright (c) 1999, 2000 John D. Polstra +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 5, 2000 +.Dt DLLOCKINIT 3 +.Os +.Sh NAME +.Nm dllockinit +.Nd register thread locking methods with the dynamic linker +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In dlfcn.h +.Ft void +.Fn dllockinit "void *context" "void *(*lock_create)(void *context)" "void (*rlock_acquire)(void *lock)" "void (*wlock_acquire)(void *lock)" "void (*lock_release)(void *lock)" "void (*lock_destroy)(void *lock)" "void (*context_destroy)(void *context)" +.Sh DESCRIPTION +.Bf Sy +Due to enhancements in the dynamic linker, this interface is no longer +needed. +It is deprecated and will be removed from future releases. +In current releases it still exists, but only as a stub which does nothing. +.Ef +.Pp +Threads packages can call +.Fn dllockinit +at initialization time to register locking functions for the dynamic +linker to use. +This enables the dynamic linker to prevent multiple +threads from entering its critical sections simultaneously. +.Pp +The +.Fa context +argument specifies an opaque context for creating locks. +The +dynamic linker will pass it to the +.Fa lock_create +function when creating the locks it needs. +When the dynamic linker +is permanently finished using the locking functions (e.g., if the +program makes a subsequent call to +.Fn dllockinit +to register new locking functions) it will call +.Fa context_destroy +to destroy the context. +.Pp +The +.Fa lock_create +argument specifies a function for creating a read/write lock. +It +must return a pointer to the new lock. +.Pp +The +.Fa rlock_acquire +and +.Fa wlock_acquire +arguments specify functions which lock a lock for reading or +writing, respectively. +The +.Fa lock_release +argument specifies a function which unlocks a lock. +Each of these +functions is passed a pointer to the lock. +.Pp +The +.Fa lock_destroy +argument specifies a function to destroy a lock. +It may be +.Dv NULL +if locks do not need to be destroyed. +The +.Fa context_destroy +argument specifies a function to destroy the context. +It may be +.Dv NULL +if the context does not need to be destroyed. +.Pp +Until +.Fn dllockinit +is called, the dynamic linker protects its critical sections using +a default locking mechanism which works by blocking the +.Dv SIGVTALRM , +.Dv SIGPROF , +and +.Dv SIGALRM +signals. +This is sufficient for many application level threads +packages, which typically use one of these signals to implement +preemption. +An application which has registered its own locking +methods with +.Fn dllockinit +can restore the default locking by calling +.Fn dllockinit +with all arguments +.Dv NULL . +.Sh SEE ALSO +.Xr rtld 1 , +.Xr signal 3 +.Sh HISTORY +The +.Fn dllockinit +function first appeared in +.Fx 4.0 . diff --git a/lib/libc/gen/dlopen.3 b/lib/libc/gen/dlopen.3 new file mode 100644 index 000000000000..340545114114 --- /dev/null +++ b/lib/libc/gen/dlopen.3 @@ -0,0 +1,437 @@ +.\" This source code is a product of Sun Microsystems, Inc. and is provided +.\" for unrestricted use provided that this legend is included on all tape +.\" media and as a part of the software program in whole or part. Users +.\" may copy or modify this source code without charge, but are not authorized +.\" to license or distribute it to anyone else except as part of a product or +.\" program developed by the user. +.\" +.\" THIS PROGRAM CONTAINS SOURCE CODE COPYRIGHTED BY SUN MICROSYSTEMS, INC. +.\" SUN MICROSYSTEMS, INC., MAKES NO REPRESENTATIONS ABOUT THE SUITABLITY +.\" OF SUCH SOURCE CODE FOR ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT +.\" EXPRESS OR IMPLIED WARRANTY OF ANY KIND. SUN MICROSYSTEMS, INC. DISCLAIMS +.\" ALL WARRANTIES WITH REGARD TO SUCH SOURCE CODE, INCLUDING ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN +.\" NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY SPECIAL, INDIRECT, +.\" INCIDENTAL, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +.\" FROM USE OF SUCH SOURCE CODE, REGARDLESS OF THE THEORY OF LIABILITY. +.\" +.\" This source code is provided with no support and without any obligation on +.\" the part of Sun Microsystems, Inc. to assist in its use, correction, +.\" modification or enhancement. +.\" +.\" SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE +.\" INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY THIS +.\" SOURCE CODE OR ANY PART THEREOF. +.\" +.\" Sun Microsystems, Inc. +.\" 2550 Garcia Avenue +.\" Mountain View, California 94043 +.\" +.\" Copyright (c) 1991 Sun Microsystems, Inc. +.\" +.Dd May 7, 2024 +.Dt DLOPEN 3 +.Os +.Sh NAME +.Nm dlopen , +.Nm fdlopen , +.Nm dlsym , +.Nm dlvsym , +.Nm dlfunc , +.Nm dlerror , +.Nm dlclose +.Nd programmatic interface to the dynamic linker +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In dlfcn.h +.Ft void * +.Fn dlopen "const char *path" "int mode" +.Ft void * +.Fn fdlopen "int fd" "int mode" +.Ft void * +.Fn dlsym "void * restrict handle" "const char * restrict symbol" +.Ft void * +.Fn dlvsym "void * restrict handle" "const char * restrict symbol" "const char * restrict version" +.Ft dlfunc_t +.Fn dlfunc "void * restrict handle" "const char * restrict symbol" +.Ft char * +.Fn dlerror "void" +.Ft int +.Fn dlclose "void *handle" +.Sh DESCRIPTION +These functions provide a simple programmatic interface to the services of the +dynamic linker. +Operations are provided to add new shared objects to a +program's address space, to obtain the address bindings of symbols +defined by such +objects, and to remove such objects when their use is no longer required. +.Pp +The +.Fn dlopen +function +provides access to the shared object in +.Fa path , +returning a descriptor that can be used for later +references to the object in calls to +.Fn dlsym , +.Fn dlvsym +and +.Fn dlclose . +If +.Fa path +was not in the address space prior to the call to +.Fn dlopen , +it is placed in the address space. +When an object is first loaded into the address space in this way, its +function +.Fn _init , +if any, is called by the dynamic linker. +If +.Fa path +has already been placed in the address space in a previous call to +.Fn dlopen , +it is not added a second time, although a reference count of +.Fn dlopen +operations on +.Fa path +is maintained. +A null pointer supplied for +.Fa path +is interpreted as a reference to the main +executable of the process. +The +.Fa mode +argument +controls the way in which external function references from the +loaded object are bound to their referents. +It must contain one of the following values, possibly ORed with +additional flags which will be described subsequently: +.Bl -tag -width RTLD_LAZYX +.It Dv RTLD_LAZY +Each external function reference is resolved when the function is first +called. +.It Dv RTLD_NOW +All external function references are bound immediately by +.Fn dlopen . +.El +.Pp +.Dv RTLD_LAZY +is normally preferred, for reasons of efficiency. +However, +.Dv RTLD_NOW +is useful to ensure that any undefined symbols are discovered during the +call to +.Fn dlopen . +.Pp +One of the following flags may be ORed into the +.Fa mode +argument: +.Bl -tag -width RTLD_NODELETE +.It Dv RTLD_GLOBAL +Symbols from this shared object and its directed acyclic graph (DAG) +of needed objects will be available for resolving undefined references +from all other shared objects. +.It Dv RTLD_LOCAL +Symbols in this shared object and its DAG of needed objects will be +available for resolving undefined references only from other objects +in the same DAG. +This is the default, but it may be specified +explicitly with this flag. +.It Dv RTLD_TRACE +When set, causes dynamic linker to exit after loading all objects +needed by this shared object and printing a summary which includes +the absolute pathnames of all objects, to standard output. +With this flag +.Fn dlopen +will return to the caller only in the case of error. +.It Dv RTLD_NODELETE +Prevents unload of the loaded object on +.Fn dlclose . +The same behaviour may be requested by +.Fl "z nodelete" +option of the static linker +.Xr ld 1 . +.It Dv RTLD_NOLOAD +Only return valid handle for the object if it is already loaded in +the process address space, otherwise +.Dv NULL +is returned. +Other mode flags may be specified, which will be applied for promotion +for the found object. +.It Dv RTLD_DEEPBIND +Symbols from the loaded library are put before global symbols when +resolving symbolic references originated from the library. +.El +.Pp +If +.Fn dlopen +fails, it returns a null pointer, and sets an error condition which may +be interrogated with +.Fn dlerror . +.Pp +The +.Fn fdlopen +function is similar to +.Fn dlopen , +but it takes the file descriptor argument +.Fa fd , +which is used for the file operations needed to load an object +into the address space. +The file descriptor +.Fa fd +is not closed by the function regardless a result of execution, +but a duplicate of the file descriptor is. +This may be important if a +.Xr lockf 3 +lock is held on the passed descriptor. +The +.Fa fd +argument -1 is interpreted as a reference to the main +executable of the process, similar to +.Va NULL +value for the +.Fa name +argument to +.Fn dlopen . +The +.Fn fdlopen +function can be used by the code that needs to perform +additional checks on the loaded objects, to prevent races with +symlinking or renames. +Applications sandboxed using +.Xr capsicum 4 +can also make beneficial use of +.Fn fdlopen . +.Pp +The +.Fn dlsym +function +returns the address binding of the symbol described in the null-terminated +character string +.Fa symbol , +as it occurs in the shared object identified by +.Fa handle . +The symbols exported by objects added to the address space by +.Fn dlopen +can be accessed only through calls to +.Fn dlsym . +Such symbols do not supersede any definition of those symbols already present +in the address space when the object is loaded, nor are they available to +satisfy normal dynamic linking references. +.Pp +If +.Fn dlsym +is called with the special +.Fa handle +.Dv NULL , +it is interpreted as a reference to the executable or shared object +from which the call +is being made. +Thus a shared object can reference its own symbols. +.Pp +If +.Fn dlsym +is called with the special +.Fa handle +.Dv RTLD_DEFAULT , +the search for the symbol follows the algorithm used for resolving +undefined symbols when objects are loaded. +The objects searched are +as follows, in the given order: +.Bl -enum +.It +The referencing object itself (or the object from which the call to +.Fn dlsym +is made), if that object was linked using the +.Fl Bsymbolic +option to +.Xr ld 1 . +.It +All objects loaded at program start-up. +.It +All objects loaded via +.Fn dlopen +with the +.Dv RTLD_GLOBAL +flag set in the +.Fa mode +argument. +.It +All objects loaded via +.Fn dlopen +which are in needed-object DAGs that also contain the referencing object. +.El +.Pp +If +.Fn dlsym +is called with the special +.Fa handle +.Dv RTLD_NEXT , +then the search for the symbol is limited to the shared objects +which were loaded after the one issuing the call to +.Fn dlsym . +Thus, if the function is called from the main program, all +the shared libraries are searched. +If it is called from a shared library, all subsequent shared +libraries are searched. +.Dv RTLD_NEXT +is useful for implementing wrappers around library functions. +For example, a wrapper function +.Fn getpid +could access the +.Dq real +.Fn getpid +with +.Li dlsym(RTLD_NEXT, \&"getpid\&") . +(Actually, the +.Fn dlfunc +interface, below, should be used, since +.Fn getpid +is a function and not a data object.) +.Pp +If +.Fn dlsym +is called with the special +.Fa handle +.Dv RTLD_SELF , +then the search for the symbol is limited to the shared object +issuing the call to +.Fn dlsym +and those shared objects which were loaded after it. +.Pp +The +.Fn dlsym +function +returns a null pointer if the symbol cannot be found, and sets an error +condition which may be queried with +.Fn dlerror . +.Pp +The +.Fn dlvsym +function behaves like +.Fn dlsym , +but takes an extra argument +.Fa version : +a null-terminated character string which is used to request a specific version +of +.Fa symbol . +.Pp +The +.Fn dlfunc +function +implements all of the behavior of +.Fn dlsym , +but has a return type which can be cast to a function pointer without +triggering compiler diagnostics. +(The +.Fn dlsym +function +returns an object pointer; in the C standard, conversions between +object and function pointer types are undefined. +Some compilers and lint utilities warn about such casts.) +The precise return type of +.Fn dlfunc +is unspecified; applications must cast it to an appropriate function pointer +type. +.Pp +The +.Fn dlerror +function +returns a null-terminated character string describing the last error that +occurred during a call to +.Fn dlopen , +.Fn dladdr , +.Fn dlinfo , +.Fn dlsym , +.Fn dlvsym , +.Fn dlfunc , +or +.Fn dlclose . +If no such error has occurred, +.Fn dlerror +returns a null pointer. +At each call to +.Fn dlerror , +the error indication is reset. +Thus in the case of two calls +to +.Fn dlerror , +where the second call follows the first immediately, the second call +will always return a null pointer. +.Pp +The +.Fn dlclose +function +deletes a reference to the shared object referenced by +.Fa handle . +If the reference count drops to 0, the object is removed from the +address space, and +.Fa handle +is rendered invalid. +Just before removing a shared object in this way, the dynamic linker +calls the object's +.Fn _fini +function, if such a function is defined by the object. +If +.Fn dlclose +is successful, it returns a value of 0. +Otherwise it returns -1, and sets an error condition that can be +interrogated with +.Fn dlerror . +.Pp +The object-intrinsic functions +.Fn _init +and +.Fn _fini +are called with no arguments, and are not expected to return values. +.Sh NOTES +ELF executables need to be linked +using the +.Fl export-dynamic +option to +.Xr ld 1 +for symbols defined in the executable to become visible to +.Fn dlsym , +.Fn dlvsym +or +.Fn dlfunc +.Pp +Other ELF platforms require linking with +.Lb libdl +to provide +.Fn dlopen +and other functions. +.Fx +does not require linking with the library, but supports it for compatibility. +.Pp +In previous implementations, it was necessary to prepend an underscore +to all external symbols in order to gain symbol +compatibility with object code compiled from the C language. +This is +still the case when using the (obsolete) +.Fl aout +option to the C language compiler. +.Sh ERRORS +The +.Fn dlopen , +.Fn fdlopen , +.Fn dlsym , +.Fn dlvsym , +and +.Fn dlfunc +functions +return a null pointer in the event of errors. +The +.Fn dlclose +function +returns 0 on success, or -1 if an error occurred. +Whenever an error has been detected, a message detailing it can be +retrieved via a call to +.Fn dlerror . +.Sh SEE ALSO +.Xr ld 1 , +.Xr rtld 1 , +.Xr dladdr 3 , +.Xr dlinfo 3 , +.Xr link 5 diff --git a/lib/libc/gen/drand48.c b/lib/libc/gen/drand48.c new file mode 100644 index 000000000000..f7f43ff20468 --- /dev/null +++ b/lib/libc/gen/drand48.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +double +drand48(void) +{ + ERAND48_BEGIN; + _DORAND48(_rand48_seed); + ERAND48_END(_rand48_seed); +} diff --git a/lib/libc/gen/dup3.3 b/lib/libc/gen/dup3.3 new file mode 100644 index 000000000000..338a9ae74c64 --- /dev/null +++ b/lib/libc/gen/dup3.3 @@ -0,0 +1,125 @@ +.\" Copyright (c) 2013 Jilles Tjoelker +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 17, 2025 +.Dt DUP3 3 +.Os +.Sh NAME +.Nm dup3 +.Nd duplicate an existing file descriptor +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In fcntl.h +.In unistd.h +.Ft int +.Fn dup3 "int oldd" "int newd" "int flags" +.Sh DESCRIPTION +The +.Fn dup3 +function +duplicates an existing object descriptor +while allowing the value of the new descriptor to be specified. +.Pp +The close-on-exec flag on the new file descriptor is determined by the +.Dv O_CLOEXEC +bit in +.Fa flags . +.Pp +The close-on-fork flag on the new file descriptor is determined by the +.Dv O_CLOFORK +bit in +.Fa flags . +.Pp +If +.Fa oldd +\*(Ne +.Fa newd +and +.Fa flags +== 0, +the behavior is identical to +.Li dup2(oldd, newd) . +.Pp +If +.Fa oldd +== +.Fa newd , +then +.Fn dup3 +fails, unlike +.Xr dup2 2 . +.Sh RETURN VALUES +The value -1 is returned if an error occurs. +The external variable +.Va errno +indicates the cause of the error. +.Sh ERRORS +The +.Fn dup3 +function fails if: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa oldd +argument is not a valid active descriptor or the +.Fa newd +argument is negative or exceeds the maximum allowable descriptor number +.It Bq Er EINVAL +The +.Fa oldd +argument is equal to the +.Fa newd +argument. +.It Bq Er EINVAL +The +.Fa flags +argument has bits set other than +.Dv O_CLOEXEC +or +.Dv O_CLOFORK . +.El +.Sh SEE ALSO +.Xr accept 2 , +.Xr close 2 , +.Xr dup2 2 , +.Xr fcntl 2 , +.Xr getdtablesize 2 , +.Xr open 2 , +.Xr pipe 2 , +.Xr socket 2 , +.Xr socketpair 2 +.Sh STANDARDS +The +.Fn dup3 +function does not conform to any standard. +.Sh HISTORY +The +.Fn dup3 +function appeared in +.Fx 10.0 . +The +.Dv O_CLOFORK +flag appeared in +.Fx 15.0 . diff --git a/lib/libc/gen/dup3.c b/lib/libc/gen/dup3.c new file mode 100644 index 000000000000..1401c1f5b607 --- /dev/null +++ b/lib/libc/gen/dup3.c @@ -0,0 +1,61 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 Jukka A. Ukkonen + * All rights reserved. + * + * This software was developed by Jukka Ukkonen for FreeBSD. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include "un-namespace.h" + +int __dup3(int, int, int); + +int +__dup3(int oldfd, int newfd, int flags) +{ + int fdflags; + + if (oldfd == newfd) { + errno = EINVAL; + return (-1); + } + + if ((flags & ~(O_CLOEXEC | O_CLOFORK)) != 0) { + errno = EINVAL; + return (-1); + } + + fdflags = ((flags & O_CLOEXEC) != 0 ? FD_CLOEXEC : 0) | + ((flags & O_CLOFORK) != 0 ? FD_CLOFORK : 0); + + return (_fcntl(oldfd, F_DUP3FD | (fdflags << F_DUP3FD_SHIFT), newfd)); +} + +__weak_reference(__dup3, dup3); +__weak_reference(__dup3, _dup3); diff --git a/lib/libc/gen/elf_utils.c b/lib/libc/gen/elf_utils.c new file mode 100644 index 000000000000..3714a0dc42b5 --- /dev/null +++ b/lib/libc/gen/elf_utils.c @@ -0,0 +1,106 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2010 Konstantin Belousov <kib@freebsd.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/auxv.h> +#include <sys/mman.h> +#include <sys/resource.h> +#include <sys/sysctl.h> + +#include <machine/tls.h> + +#include <link.h> +#include <stddef.h> +#include <string.h> + +#include "libc_private.h" + +void __pthread_map_stacks_exec(void); + +int +__elf_phdr_match_addr(struct dl_phdr_info *phdr_info, void *addr) +{ + const Elf_Phdr *ph; + int i; + + for (i = 0; i < phdr_info->dlpi_phnum; i++) { + ph = &phdr_info->dlpi_phdr[i]; + if (ph->p_type != PT_LOAD) + continue; + + /* ELFv1 ABI for powerpc64 passes function descriptor + * pointers around, not function pointers. The function + * descriptors live in .opd, which is a non-executable segment. + * The PF_X check would therefore make all address checks fail, + * causing a crash in some instances. Don't skip over + * non-executable segments in the ELFv1 powerpc64 case. + */ +#if !defined(__powerpc64__) || (defined(_CALL_ELF) && _CALL_ELF == 2) + if ((ph->p_flags & PF_X) == 0) + continue; +#endif + + if (phdr_info->dlpi_addr + ph->p_vaddr <= (uintptr_t)addr && + (uintptr_t)addr < phdr_info->dlpi_addr + + ph->p_vaddr + ph->p_memsz) + break; + } + return (i != phdr_info->dlpi_phnum); +} + +void +__libc_map_stacks_exec(void) +{ + int mib[2]; + struct rlimit rlim; + u_long usrstack, stacksz; + size_t len; + + if (_elf_aux_info(AT_USRSTACKBASE, &usrstack, sizeof(usrstack)) != 0) { + mib[0] = CTL_KERN; + mib[1] = KERN_USRSTACK; + len = sizeof(usrstack); + if (sysctl(mib, nitems(mib), &usrstack, &len, NULL, 0) == -1) + return; + } + if (_elf_aux_info(AT_USRSTACKLIM, &stacksz, sizeof(stacksz)) != 0) { + if (getrlimit(RLIMIT_STACK, &rlim) == -1) + return; + stacksz = rlim.rlim_cur; + } + mprotect((void *)(uintptr_t)(usrstack - stacksz), stacksz, + _rtld_get_stack_prot()); +} + +#pragma weak __pthread_map_stacks_exec +void +__pthread_map_stacks_exec(void) +{ + + ((void (*)(void))__libc_interposing[INTERPOS_map_stacks_exec])(); +} diff --git a/lib/libc/gen/erand48.c b/lib/libc/gen/erand48.c new file mode 100644 index 000000000000..38d4774a9fe6 --- /dev/null +++ b/lib/libc/gen/erand48.c @@ -0,0 +1,24 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +double +erand48(unsigned short xseed[3]) +{ + uint48 tmp; + + ERAND48_BEGIN; + DORAND48(tmp, xseed); + ERAND48_END(tmp); +} diff --git a/lib/libc/gen/err.3 b/lib/libc/gen/err.3 new file mode 100644 index 000000000000..088ead71239b --- /dev/null +++ b/lib/libc/gen/err.3 @@ -0,0 +1,242 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd March 29, 2012 +.Dt ERR 3 +.Os +.Sh NAME +.Nm err , +.Nm verr , +.Nm errc , +.Nm verrc , +.Nm errx , +.Nm verrx , +.Nm warn , +.Nm vwarn , +.Nm warnc , +.Nm vwarnc , +.Nm warnx , +.Nm vwarnx , +.Nm err_set_exit , +.Nm err_set_file +.Nd formatted error messages +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In err.h +.Ft void +.Fn err "int eval" "const char *fmt" "..." +.Ft void +.Fn err_set_exit "void (*exitf)(int)" +.Ft void +.Fn err_set_file "void *vfp" +.Ft void +.Fn errc "int eval" "int code" "const char *fmt" "..." +.Ft void +.Fn errx "int eval" "const char *fmt" "..." +.Ft void +.Fn warn "const char *fmt" "..." +.Ft void +.Fn warnc "int code" "const char *fmt" "..." +.Ft void +.Fn warnx "const char *fmt" "..." +.In stdarg.h +.Ft void +.Fn verr "int eval" "const char *fmt" "va_list args" +.Ft void +.Fn verrc "int eval" "int code" "const char *fmt" "va_list args" +.Ft void +.Fn verrx "int eval" "const char *fmt" "va_list args" +.Ft void +.Fn vwarn "const char *fmt" "va_list args" +.Ft void +.Fn vwarnc "int code" "const char *fmt" "va_list args" +.Ft void +.Fn vwarnx "const char *fmt" "va_list args" +.Sh DESCRIPTION +The +.Fn err +and +.Fn warn +family of functions display a formatted error message on the standard +error output, or on another file specified using the +.Fn err_set_file +function. +In all cases, the last component of the program name, a colon character, +and a space are output. +If the +.Fa fmt +argument is not NULL, the +.Xr printf 3 Ns +-like formatted error message is output. +The output is terminated by a newline character. +.Pp +The +.Fn err , +.Fn errc , +.Fn verr , +.Fn verrc , +.Fn warn , +.Fn warnc , +.Fn vwarn , +and +.Fn vwarnc +functions append an error message obtained from +.Xr strerror 3 +based on a supplied error code value or the global variable +.Va errno , +preceded by another colon and space unless the +.Fa fmt +argument is +.Dv NULL . +.Pp +In the case of the +.Fn errc , +.Fn verrc , +.Fn warnc , +and +.Fn vwarnc +functions, +the +.Fa code +argument is used to look up the error message. +.Pp +The +.Fn err , +.Fn verr , +.Fn warn , +and +.Fn vwarn +functions use the global variable +.Va errno +to look up the error message. +.Pp +The +.Fn errx +and +.Fn warnx +functions do not append an error message. +.Pp +The +.Fn err , +.Fn verr , +.Fn errc , +.Fn verrc , +.Fn errx , +and +.Fn verrx +functions do not return, but exit with the value of the argument +.Fa eval . +It is recommended that the standard values defined in +.Xr sysexits 3 +be used for the value of +.Fa eval . +The +.Fn err_set_exit +function can be used to specify a function which is called before +.Xr exit 3 +to perform any necessary cleanup; passing a null function pointer for +.Va exitf +resets the hook to do nothing. +The +.Fn err_set_file +function sets the output stream used by the other functions. +Its +.Fa vfp +argument must be either a pointer to an open stream +(possibly already converted to void *) +or a null pointer +(in which case the output stream is set to standard error). +.Sh EXAMPLES +Display the current errno information string and exit: +.Bd -literal -offset indent +if ((p = malloc(size)) == NULL) + err(EX_OSERR, NULL); +if ((fd = open(file_name, O_RDONLY, 0)) == -1) + err(EX_NOINPUT, "%s", file_name); +.Ed +.Pp +Display an error message and exit: +.Bd -literal -offset indent +if (tm.tm_hour < START_TIME) + errx(EX_DATAERR, "too early, wait until %s", + start_time_string); +.Ed +.Pp +Warn of an error: +.Bd -literal -offset indent +if ((fd = open(raw_device, O_RDONLY, 0)) == -1) + warnx("%s: %s: trying the block device", + raw_device, strerror(errno)); +if ((fd = open(block_device, O_RDONLY, 0)) == -1) + err(EX_OSFILE, "%s", block_device); +.Ed +.Pp +Warn of an error without using the global variable +.Va errno : +.Bd -literal -offset indent +error = my_function(); /* returns a value from <errno.h> */ +if (error != 0) + warnc(error, "my_function"); +.Ed +.Sh SEE ALSO +.Xr exit 3 , +.Xr fmtmsg 3 , +.Xr printf 3 , +.Xr strerror 3 , +.Xr sysexits 3 +.Sh STANDARDS +The +.Fn err +and +.Fn warn +families of functions are +.Bx +extensions. +As such they should not be used in truly portable code. +Use +.Fn strerror +or similar functions instead. +.Sh HISTORY +The +.Fn err +and +.Fn warn +functions first appeared in +.Bx 4.4 . +The +.Fn err_set_exit +and +.Fn err_set_file +functions first appeared in +.Fx 2.1 . +The +.Fn errc +and +.Fn warnc +functions first appeared in +.Fx 3.0 . diff --git a/lib/libc/gen/err.c b/lib/libc/gen/err.c new file mode 100644 index 000000000000..16cbe27693e7 --- /dev/null +++ b/lib/libc/gen/err.c @@ -0,0 +1,223 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/exterrvar.h> +#include <err.h> +#include <errno.h> +#include <exterr.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "un-namespace.h" + +#include "libc_private.h" + +static FILE *err_file; /* file to use for error output */ +static void (*err_exit)(int); + +static void verrci(bool doexterr, int eval, int code, const char *fmt, + va_list ap) __printf0like(4, 0) __dead2; +static void vwarnci(bool doexterr, int code, const char *fmt, va_list ap) + __printf0like(3, 0); + +/* + * This is declared to take a `void *' so that the caller is not required + * to include <stdio.h> first. However, it is really a `FILE *', and the + * manual page documents it as such. + */ +void +err_set_file(void *fp) +{ + if (fp) + err_file = fp; + else + err_file = stderr; +} + +void +err_set_exit(void (*ef)(int)) +{ + err_exit = ef; +} + +__weak_reference(_err, err); + +void +_err(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrci(true, eval, errno, fmt, ap); + va_end(ap); +} + +void +verr(int eval, const char *fmt, va_list ap) +{ + verrci(true, eval, errno, fmt, ap); +} + +void +errc(int eval, int code, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrci(false, eval, code, fmt, ap); + va_end(ap); +} + +void +verrc(int eval, int code, const char *fmt, va_list ap) +{ + verrci(false, eval, code, fmt, ap); +} + +static void +vexterr(bool doexterr, int code, const char *fmt, va_list ap) +{ + char exterr[UEXTERROR_MAXLEN]; /* libc knows the buffer size */ + int extstatus; + + if (doexterr) + extstatus = uexterr_gettext(exterr, sizeof(exterr)); + if (err_file == NULL) + err_set_file(NULL); + fprintf(err_file, "%s: ", _getprogname()); + if (fmt != NULL) { + vfprintf(err_file, fmt, ap); + fprintf(err_file, ": "); + } + fprintf(err_file, "%s", strerror(code)); + if (doexterr && extstatus == 0 && exterr[0] != '\0') + fprintf(err_file, " (extended error %s)", exterr); + fprintf(err_file, "\n"); +} + +static void +verrci(bool doexterr, int eval, int code, const char *fmt, va_list ap) +{ + vexterr(doexterr, code, fmt, ap); + if (err_exit) + err_exit(eval); + exit(eval); +} + +void +errx(int eval, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + verrx(eval, fmt, ap); + va_end(ap); +} + +void +verrx(int eval, const char *fmt, va_list ap) +{ + if (err_file == NULL) + err_set_file(NULL); + fprintf(err_file, "%s: ", _getprogname()); + if (fmt != NULL) + vfprintf(err_file, fmt, ap); + fprintf(err_file, "\n"); + if (err_exit) + err_exit(eval); + exit(eval); +} + +__weak_reference(_warn, warn); + +void +_warn(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnc(errno, fmt, ap); + va_end(ap); +} + +void +vwarn(const char *fmt, va_list ap) +{ + vwarnc(errno, fmt, ap); +} + +void +warnc(int code, const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnc(code, fmt, ap); + va_end(ap); +} + +void +vwarnc(int code, const char *fmt, va_list ap) +{ + vwarnci(false, code, fmt, ap); +} + +static void +vwarnci(bool doexterr, int code, const char *fmt, va_list ap) +{ + int saved_errno; + + saved_errno = errno; + vexterr(doexterr, code, fmt, ap); + errno = saved_errno; +} + +void +warnx(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vwarnx(fmt, ap); + va_end(ap); +} + +void +vwarnx(const char *fmt, va_list ap) +{ + int saved_errno; + + saved_errno = errno; + if (err_file == NULL) + err_set_file(NULL); + fprintf(err_file, "%s: ", _getprogname()); + if (fmt != NULL) + vfprintf(err_file, fmt, ap); + fprintf(err_file, "\n"); + errno = saved_errno; +} diff --git a/lib/libc/gen/errlst.c b/lib/libc/gen/errlst.c new file mode 100644 index 000000000000..a73fa06feb5e --- /dev/null +++ b/lib/libc/gen/errlst.c @@ -0,0 +1,222 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1982, 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <errno.h> +#include <stdio.h> +#include "errlst.h" + +const char __uprefix[] = "Unknown error"; + +const char *const sys_errlist[] = { + "No error: 0", /* 0 - ENOERROR */ + "Operation not permitted", /* 1 - EPERM */ + "No such file or directory", /* 2 - ENOENT */ + "No such process", /* 3 - ESRCH */ + "Interrupted system call", /* 4 - EINTR */ + "Input/output error", /* 5 - EIO */ + "Device not configured", /* 6 - ENXIO */ + "Argument list too long", /* 7 - E2BIG */ + "Exec format error", /* 8 - ENOEXEC */ + "Bad file descriptor", /* 9 - EBADF */ + "No child processes", /* 10 - ECHILD */ + "Resource deadlock avoided", /* 11 - EDEADLK */ + "Cannot allocate memory", /* 12 - ENOMEM */ + "Permission denied", /* 13 - EACCES */ + "Bad address", /* 14 - EFAULT */ + "Block device required", /* 15 - ENOTBLK */ + "Device busy", /* 16 - EBUSY */ + "File exists", /* 17 - EEXIST */ + "Cross-device link", /* 18 - EXDEV */ + "Operation not supported by device", /* 19 - ENODEV */ + "Not a directory", /* 20 - ENOTDIR */ + "Is a directory", /* 21 - EISDIR */ + "Invalid argument", /* 22 - EINVAL */ + "Too many open files in system", /* 23 - ENFILE */ + "Too many open files", /* 24 - EMFILE */ + "Inappropriate ioctl for device", /* 25 - ENOTTY */ + "Text file busy", /* 26 - ETXTBSY */ + "File too large", /* 27 - EFBIG */ + "No space left on device", /* 28 - ENOSPC */ + "Illegal seek", /* 29 - ESPIPE */ + "Read-only file system", /* 30 - EROFS */ + "Too many links", /* 31 - EMLINK */ + "Broken pipe", /* 32 - EPIPE */ + +/* math software */ + "Numerical argument out of domain", /* 33 - EDOM */ + "Result too large", /* 34 - ERANGE */ + +/* non-blocking and interrupt i/o */ + "Resource temporarily unavailable", /* 35 - EAGAIN */ + /* 35 - EWOULDBLOCK */ + "Operation now in progress", /* 36 - EINPROGRESS */ + "Operation already in progress", /* 37 - EALREADY */ + +/* ipc/network software -- argument errors */ + "Socket operation on non-socket", /* 38 - ENOTSOCK */ + "Destination address required", /* 39 - EDESTADDRREQ */ + "Message too long", /* 40 - EMSGSIZE */ + "Protocol wrong type for socket", /* 41 - EPROTOTYPE */ + "Protocol not available", /* 42 - ENOPROTOOPT */ + "Protocol not supported", /* 43 - EPROTONOSUPPORT */ + "Socket type not supported", /* 44 - ESOCKTNOSUPPORT */ + "Operation not supported", /* 45 - EOPNOTSUPP */ + "Protocol family not supported", /* 46 - EPFNOSUPPORT */ + /* 47 - EAFNOSUPPORT */ + "Address family not supported by protocol family", + "Address already in use", /* 48 - EADDRINUSE */ + "Can't assign requested address", /* 49 - EADDRNOTAVAIL */ + +/* ipc/network software -- operational errors */ + "Network is down", /* 50 - ENETDOWN */ + "Network is unreachable", /* 51 - ENETUNREACH */ + "Network dropped connection on reset", /* 52 - ENETRESET */ + "Software caused connection abort", /* 53 - ECONNABORTED */ + "Connection reset by peer", /* 54 - ECONNRESET */ + "No buffer space available", /* 55 - ENOBUFS */ + "Socket is already connected", /* 56 - EISCONN */ + "Socket is not connected", /* 57 - ENOTCONN */ + "Can't send after socket shutdown", /* 58 - ESHUTDOWN */ + "Too many references: can't splice", /* 59 - ETOOMANYREFS */ + "Operation timed out", /* 60 - ETIMEDOUT */ + "Connection refused", /* 61 - ECONNREFUSED */ + + "Too many levels of symbolic links", /* 62 - ELOOP */ + "File name too long", /* 63 - ENAMETOOLONG */ + +/* should be rearranged */ + "Host is down", /* 64 - EHOSTDOWN */ + "No route to host", /* 65 - EHOSTUNREACH */ + "Directory not empty", /* 66 - ENOTEMPTY */ + +/* quotas & mush */ + "Too many processes", /* 67 - EPROCLIM */ + "Too many users", /* 68 - EUSERS */ + "Disc quota exceeded", /* 69 - EDQUOT */ + +/* Network File System */ + "Stale NFS file handle", /* 70 - ESTALE */ + "Too many levels of remote in path", /* 71 - EREMOTE */ + "RPC struct is bad", /* 72 - EBADRPC */ + "RPC version wrong", /* 73 - ERPCMISMATCH */ + "RPC prog. not avail", /* 74 - EPROGUNAVAIL */ + "Program version wrong", /* 75 - EPROGMISMATCH */ + "Bad procedure for program", /* 76 - EPROCUNAVAIL */ + + "No locks available", /* 77 - ENOLCK */ + "Function not implemented", /* 78 - ENOSYS */ + "Inappropriate file type or format", /* 79 - EFTYPE */ + "Authentication error", /* 80 - EAUTH */ + "Need authenticator", /* 81 - ENEEDAUTH */ + "Identifier removed", /* 82 - EIDRM */ + "No message of desired type", /* 83 - ENOMSG */ + "Value too large to be stored in data type", /* 84 - EOVERFLOW */ + "Operation canceled", /* 85 - ECANCELED */ + "Illegal byte sequence", /* 86 - EILSEQ */ + "Attribute not found", /* 87 - ENOATTR */ + +/* General */ + "Programming error", /* 88 - EDOOFUS */ + + "Bad message", /* 89 - EBADMSG */ + "Multihop attempted", /* 90 - EMULTIHOP */ + "Link has been severed", /* 91 - ENOLINK */ + "Protocol error", /* 92 - EPROTO */ + "Capabilities insufficient", /* 93 - ENOTCAPABLE */ + "Not permitted in capability mode", /* 94 - ECAPMODE */ + "State not recoverable", /* 95 - ENOTRECOVERABLE */ + "Previous owner died", /* 96 - EOWNERDEAD */ + "Integrity check failed", /* 97 - EINTEGRITY */ + +/* + * Reserved space in sys_errlist, take the next slot for a next error code. + * Reserve prevents the array size from changing for some time. + */ + __uprefix, /* 98 */ + __uprefix, /* 99 */ + __uprefix, /* 100 */ + __uprefix, /* 101 */ + __uprefix, /* 102 */ + __uprefix, /* 103 */ + __uprefix, /* 104 */ + __uprefix, /* 105 */ + __uprefix, /* 106 */ + __uprefix, /* 107 */ + __uprefix, /* 108 */ + __uprefix, /* 109 */ + __uprefix, /* 110 */ + __uprefix, /* 111 */ + __uprefix, /* 112 */ + __uprefix, /* 113 */ + __uprefix, /* 114 */ + __uprefix, /* 115 */ + __uprefix, /* 116 */ + __uprefix, /* 117 */ + __uprefix, /* 118 */ + __uprefix, /* 119 */ + __uprefix, /* 120 */ + __uprefix, /* 121 */ + __uprefix, /* 122 */ + __uprefix, /* 123 */ + __uprefix, /* 124 */ + __uprefix, /* 125 */ + __uprefix, /* 126 */ + __uprefix, /* 127 */ + __uprefix, /* 128 */ + __uprefix, /* 129 */ + __uprefix, /* 130 */ + __uprefix, /* 131 */ + __uprefix, /* 132 */ + __uprefix, /* 133 */ + __uprefix, /* 134 */ + __uprefix, /* 135 */ + __uprefix, /* 136 */ + __uprefix, /* 137 */ + __uprefix, /* 138 */ + __uprefix, /* 139 */ + __uprefix, /* 140 */ + __uprefix, /* 141 */ + __uprefix, /* 142 */ + __uprefix, /* 143 */ + __uprefix, /* 144 */ + __uprefix, /* 145 */ + __uprefix, /* 146 */ + __uprefix, /* 147 */ + __uprefix, /* 148 */ + __uprefix, /* 149 */ + __uprefix, /* 150 */ +}; +const int sys_nerr = ELAST + 1; + +#ifdef PIC +__strong_reference(sys_errlist, __hidden_sys_errlist); +__strong_reference(sys_nerr, __hidden_sys_nerr); +#endif diff --git a/lib/libc/gen/eventfd.c b/lib/libc/gen/eventfd.c new file mode 100644 index 000000000000..44a33915c2fb --- /dev/null +++ b/lib/libc/gen/eventfd.c @@ -0,0 +1,51 @@ +/*- + * SPDX-License-Identifier: MIT + * + * Copyright (c) 2005-2020 Rich Felker, et al. + * Copyright (c) 2020 Val Packett + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "namespace.h" +#include <sys/eventfd.h> +#include <sys/specialfd.h> +#include <unistd.h> +#include "un-namespace.h" +#include "libc_private.h" + +int eventfd(unsigned int initval, int flags) +{ + struct specialfd_eventfd args; + + args.initval = initval; + args.flags = flags; + return (__sys___specialfd(SPECIALFD_EVENTFD, &args, sizeof(args))); +} + +int eventfd_read(int fd, eventfd_t *value) +{ + return (sizeof(*value) == _read(fd, value, sizeof(*value)) ? 0 : -1); +} + +int eventfd_write(int fd, eventfd_t value) +{ + return (sizeof(value) == _write(fd, &value, sizeof(value)) ? 0 : -1); +} diff --git a/lib/libc/gen/exec.3 b/lib/libc/gen/exec.3 new file mode 100644 index 000000000000..41ab18fa89ef --- /dev/null +++ b/lib/libc/gen/exec.3 @@ -0,0 +1,399 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd December 11, 2023 +.Dt EXEC 3 +.Os +.Sh NAME +.Nm execl , +.Nm execlp , +.Nm execle , +.Nm exect , +.Nm execv , +.Nm execvp , +.Nm execvpe , +.Nm execvP +.Nd execute a file +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Vt extern char **environ ; +.Ft int +.Fn execl "const char *path" "const char *arg" ... NULL +.Ft int +.Fn execlp "const char *file" "const char *arg" ... NULL +.Ft int +.Fn execle "const char *path" "const char *arg" ... NULL "char *const envp[]" +.Ft int +.Fn exect "const char *path" "char *const argv[]" "char *const envp[]" +.Ft int +.Fn execv "const char *path" "char *const argv[]" +.Ft int +.Fn execvp "const char *file" "char *const argv[]" +.Ft int +.Fn execvpe "const char *file" "char *const argv[]" "char *const envp[]" +.Ft int +.Fn execvP "const char *file" "const char *search_path" "char *const argv[]" +.Sh DESCRIPTION +The +.Nm exec +family of functions replaces the current process image with a +new process image. +The functions described in this manual page are front-ends for the function +.Xr execve 2 . +(See the manual page for +.Xr execve 2 +for detailed information about the replacement of the current process.) +.Pp +The initial argument for these functions is the pathname of a file which +is to be executed. +.Pp +The +.Fa "const char *arg" +and subsequent ellipses in the +.Fn execl , +.Fn execlp , +and +.Fn execle +functions can be thought of as +.Em arg0 , +.Em arg1 , +\&..., +.Em argn . +Together they describe a list of one or more pointers to null-terminated +strings that represent the argument list available to the executed program. +The first argument, by convention, should point to the file name associated +with the file being executed. +The list of arguments +.Em must +be terminated by a +.Dv NULL +pointer. +.Pp +The +.Fn exect , +.Fn execv , +.Fn execvp , +.Fn execvpe , +and +.Fn execvP +functions provide an array of pointers to null-terminated strings that +represent the argument list available to the new program. +The first argument, by convention, should point to the file name associated +with the file being executed. +The array of pointers +.Sy must +be terminated by a +.Dv NULL +pointer. +.Pp +The +.Fn execle , +.Fn exect , +and +.Fn execvpe +functions also specify the environment of the executed process by following +the +.Dv NULL +pointer that terminates the list of arguments in the argument list +or the pointer to the argv array with an additional argument. +This additional argument is an array of pointers to null-terminated strings +and +.Em must +be terminated by a +.Dv NULL +pointer. +The other functions take the environment for the new process image from the +external variable +.Va environ +in the current process. +.Pp +Some of these functions have special semantics. +.Pp +The functions +.Fn execlp , +.Fn execvp , +.Fn execvpe , +and +.Fn execvP +will duplicate the actions of the shell in searching for an executable file +if the specified file name does not contain a slash +.Dq Li / +character. +For +.Fn execlp +and +.Fn execvp , +.Fn execvpe , +search path is the path specified in the environment by +.Dq Ev PATH +variable. +If this variable is not specified, +the default path is set according to the +.Dv _PATH_DEFPATH +definition in +.In paths.h , +which is set to +.Dq Ev /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin . +For +.Fn execvP , +the search path is specified as an argument to the function. +In addition, certain errors are treated specially. +.Pp +If an error is ambiguous (for simplicity, we shall consider all +errors except +.Er ENOEXEC +as being ambiguous here, although only the critical error +.Er EACCES +is really ambiguous), +then these functions will act as if they stat the file to determine +whether the file exists and has suitable execute permissions. +If it does, they will return immediately with the global variable +.Va errno +restored to the value set by +.Fn execve . +Otherwise, the search will be continued. +If the search completes without performing a successful +.Fn execve +or terminating due to an error, +these functions will return with the global variable +.Va errno +set to +.Er EACCES +or +.Er ENOENT +according to whether at least one file with suitable execute permissions +was found. +.Pp +If the header of a file is not recognized (the attempted +.Fn execve +returned +.Er ENOEXEC ) , +these functions will execute the shell with the path of +the file as its first argument. +(If this attempt fails, no further searching is done.) +.Pp +The function +.Fn exect +executes a file with the program tracing facilities enabled (see +.Xr ptrace 2 ) . +.Sh RETURN VALUES +If any of the +.Fn exec +functions returns, an error will have occurred. +The return value is \-1, and the global variable +.Va errno +will be set to indicate the error. +.Sh FILES +.Bl -tag -width /bin/sh -compact +.It Pa /bin/sh +The shell. +.El +.Sh COMPATIBILITY +Historically, the default path for the +.Fn execlp +and +.Fn execvp +functions was +.Dq Pa :/bin:/usr/bin . +This was changed to remove the current directory to enhance system +security. +.Pp +The behavior of +.Fn execlp +and +.Fn execvp +when errors occur while attempting to execute the file is not quite historic +practice, and has not traditionally been documented and is not specified +by the +.Tn POSIX +standard. +.Pp +Traditionally, the functions +.Fn execlp +and +.Fn execvp +ignored all errors except for the ones described above and +.Er ETXTBSY , +upon which they retried after sleeping for several seconds, and +.Er ENOMEM +and +.Er E2BIG , +upon which they returned. +They now return for +.Er ETXTBSY , +and determine existence and executability more carefully. +In particular, +.Er EACCES +for inaccessible directories in the path prefix is no longer +confused with +.Er EACCES +for files with unsuitable execute permissions. +In +.Bx 4.4 , +they returned upon all errors except +.Er EACCES , +.Er ENOENT , +.Er ENOEXEC +and +.Er ETXTBSY . +This was inferior to the traditional error handling, +since it breaks the ignoring of errors for path prefixes +and only improves the handling of the unusual ambiguous error +.Er EFAULT +and the unusual error +.Er EIO . +The behaviour was changed to match the behaviour of +.Xr sh 1 . +.Sh ERRORS +The +.Fn execl , +.Fn execle , +.Fn execlp , +.Fn execvp , +.Fn execvpe , +and +.Fn execvP +functions +may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr execve 2 +and +.Xr malloc 3 . +.Pp +The +.Fn exect +and +.Fn execv +functions +may fail and set +.Va errno +for any of the errors specified for the library function +.Xr execve 2 . +.Sh SEE ALSO +.Xr sh 1 , +.Xr execve 2 , +.Xr fork 2 , +.Xr ktrace 2 , +.Xr ptrace 2 , +.Xr environ 7 +.Sh STANDARDS +The +.Fn execl , +.Fn execv , +.Fn execle , +.Fn execlp +and +.Fn execvp +functions +conform to +.St -p1003.1-88 . +The +.Fn execvpe +function is a GNU extension. +.Sh HISTORY +The +.Fn exec +function appeared in +.At v1 . +The +.Fn execl +and +.Fn execv +functions appeared in +.At v2 . +The +.Fn execlp , +.Fn execle , +.Fn execve , +and +.Fn execvp +functions appeared in +.At v7 . +The +.Fn execvP +function first appeared in +.Fx 5.2 . +The +.Fn execvpe +function first appeared in +.Fx 14.1 . +.Sh BUGS +The type of the +.Fa argv +and +.Fa envp +parameters to +.Fn execle , +.Fn exect , +.Fn execv , +.Fn execvp , +.Fn execvpe , +and +.Fn execvP +is a historical accident and no sane implementation should modify the provided +strings. +The bogus parameter types trigger false positives from +.Li const +correctness analyzers. +On +.Fx , +the +.Fn __DECONST +macro may be used to work around this limitation. +.Pp +Due to a fluke of the C standard, on platforms other than +.Fx +the definition of +.Dv NULL +may be the untyped number zero, rather than a +.Ad (void *)0 +expression. +To distinguish the concepts, they are referred to as a +.Dq null pointer constant +and a +.Dq null pointer , +respectively. +On exotic computer architectures that +.Fx +does not support, the null pointer constant and null pointer may have a +different representation. +In general, where this document and others reference a +.Dv NULL +value, they actually imply a null pointer. +E.g., for portability to non-FreeBSD operating systems on exotic computer +architectures, one may use +.Li (char *)NULL +in place of +.Dv NULL +when invoking +.Fn execl , +.Fn execle , +and +.Fn execlp . diff --git a/lib/libc/gen/exec.c b/lib/libc/gen/exec.c new file mode 100644 index 000000000000..12020a79f6b4 --- /dev/null +++ b/lib/libc/gen/exec.c @@ -0,0 +1,369 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/stat.h> +#include <assert.h> +#include <errno.h> +#include <unistd.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <paths.h> + +#include <stdarg.h> +#include "un-namespace.h" +#include "libc_private.h" + +static const char execvPe_err_preamble[] = "execvP: "; +static const char execvPe_err_trailer[] = ": path too long\n"; + +int +execl(const char *name, const char *arg, ...) +{ + va_list ap; + const char **argv; + int n; + + va_start(ap, arg); + n = 1; + while (va_arg(ap, char *) != NULL) + n++; + va_end(ap); + argv = alloca((n + 1) * sizeof(*argv)); + if (argv == NULL) { + errno = ENOMEM; + return (-1); + } + va_start(ap, arg); + n = 1; + argv[0] = arg; + while ((argv[n] = va_arg(ap, char *)) != NULL) + n++; + va_end(ap); + return (_execve(name, __DECONST(char **, argv), environ)); +} + +int +execle(const char *name, const char *arg, ...) +{ + va_list ap; + const char **argv; + char **envp; + int n; + + va_start(ap, arg); + n = 1; + while (va_arg(ap, char *) != NULL) + n++; + va_end(ap); + argv = alloca((n + 1) * sizeof(*argv)); + if (argv == NULL) { + errno = ENOMEM; + return (-1); + } + va_start(ap, arg); + n = 1; + argv[0] = arg; + while ((argv[n] = va_arg(ap, char *)) != NULL) + n++; + envp = va_arg(ap, char **); + va_end(ap); + return (_execve(name, __DECONST(char **, argv), envp)); +} + +int +execlp(const char *name, const char *arg, ...) +{ + va_list ap; + const char **argv; + int n; + + va_start(ap, arg); + n = 1; + while (va_arg(ap, char *) != NULL) + n++; + va_end(ap); + argv = alloca((n + 1) * sizeof(*argv)); + if (argv == NULL) { + errno = ENOMEM; + return (-1); + } + va_start(ap, arg); + n = 1; + argv[0] = arg; + while ((argv[n] = va_arg(ap, char *)) != NULL) + n++; + va_end(ap); + return (execvp(name, __DECONST(char **, argv))); +} + +int +execv(const char *name, char * const *argv) +{ + (void)_execve(name, argv, environ); + return (-1); +} + +int +execvp(const char *name, char * const *argv) +{ + return (__libc_execvpe(name, argv, environ)); +} + +/* + * Returns 0 if we don't consider this a terminal condition, -1 if we do. + */ +static int +execvPe_prog(const char *path, char * const *argv, char * const *envp) +{ + struct stat sb; + const char **memp; + size_t cnt; + int save_errno; + + (void)_execve(path, argv, envp); + /* Grouped roughly by never terminal vs. usually terminal conditions */ + switch (errno) { + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + case ENOTDIR: + /* Non-terminal: property of the path we're trying */ + break; + case ENOEXEC: + /* + * Failures here are considered terminal because we must handle + * this via the ENOEXEC fallback path; doing any further + * searching would be categorically incorrect. + */ + + for (cnt = 0; argv[cnt] != NULL; ++cnt) + ; + + /* + * cnt may be 0 above; always allocate at least + * 3 entries so that we can at least fit "sh", path, and + * the NULL terminator. We can rely on cnt to take into + * account the NULL terminator in all other scenarios, + * as we drop argv[0]. + */ + memp = alloca(MAX(3, cnt + 2) * sizeof(char *)); + assert(memp != NULL); + if (cnt > 0) { + memp[0] = argv[0]; + memp[1] = path; + memcpy(&memp[2], &argv[1], cnt * sizeof(char *)); + } else { + memp[0] = "sh"; + memp[1] = path; + memp[2] = NULL; + } + + (void)_execve(_PATH_BSHELL, __DECONST(char **, memp), envp); + return (-1); + case ENOMEM: + case E2BIG: + /* Terminal: persistent condition */ + return (-1); + case ETXTBSY: + /* + * Terminal: we used to retry here, but sh(1) doesn't. + */ + return (-1); + default: + /* + * EACCES may be for an inaccessible directory or + * a non-executable file. Call stat() to decide + * which. This also handles ambiguities for EFAULT + * and EIO, and undocumented errors like ESTALE. + * We hope that the race for a stat() is unimportant. + */ + save_errno = errno; + if (stat(path, &sb) == -1) { + /* + * We force errno to ENOENT here to disambiguate the + * EACCESS case; the results of execve(2) are somewhat + * inconclusive because either the file did not exist or + * we just don't have search permissions, but the caller + * only really wants to see EACCES if the file did exist + * but was not accessible. + */ + if (save_errno == EACCES) + errno = ENOENT; + break; + } + + errno = save_errno; + + /* + * Non-terminal: the file did exist and we just didn't have + * access to it, so we surface the EACCES and let the search + * continue for a candidate that we do have access to. + */ + if (errno == EACCES) + break; + + /* + * All other errors here are terminal, as prescribed by exec(3). + */ + return (-1); + } + + return (0); +} + +static int +execvPe(const char *name, const char *path, char * const *argv, + char * const *envp) +{ + char buf[MAXPATHLEN]; + size_t ln, lp; + const char *np, *op, *p; + bool eacces; + + eacces = false; + + /* If it's an absolute or relative path name, it's easy. */ + if (strchr(name, '/') != NULL) { + /* + * We ignore non-terminal conditions because we don't have any + * further paths to try -- we can just bubble up the errno from + * execve(2) here. + */ + (void)execvPe_prog(name, argv, envp); + return (-1); + } + + /* If it's an empty path name, fail in the usual POSIX way. */ + if (*name == '\0') { + errno = ENOENT; + return (-1); + } + + op = path; + ln = strlen(name); + while (op != NULL) { + np = strchrnul(op, ':'); + + /* + * It's a SHELL path -- double, leading and trailing colons + * mean the current directory. + */ + if (np == op) { + /* Empty component. */ + p = "."; + lp = 1; + } else { + /* Non-empty component. */ + p = op; + lp = np - op; + } + + /* Advance to the next component or terminate after this. */ + if (*np == '\0') + op = NULL; + else + op = np + 1; + + /* + * If the path is too long, then complain. This is a possible + * security issue: given a way to make the path too long, the + * user may execute the wrong program. + * + * Remember to exercise caution here with assembling our final + * buf and any output, as we may be running in a vfork() context + * via posix_spawnp(). + */ + if (lp + ln + 2 > sizeof(buf)) { + (void)_write(STDERR_FILENO, execvPe_err_preamble, + sizeof(execvPe_err_preamble) - 1); + (void)_write(STDERR_FILENO, p, lp); + (void)_write(STDERR_FILENO, execvPe_err_trailer, + sizeof(execvPe_err_trailer) - 1); + + continue; + } + + memcpy(&buf[0], p, lp); + buf[lp] = '/'; + memcpy(&buf[lp + 1], name, ln); + buf[lp + ln + 1] = '\0'; + + /* + * For terminal conditions we can just return immediately. If + * it was non-terminal, we just need to note if we had an + * EACCES -- execvPe_prog would do a stat(2) and leave us with + * an errno of EACCES only if the file did exist; otherwise it + * would coerce it to an ENOENT because we may not know if a + * file actually existed there or not. + */ + if (execvPe_prog(buf, argv, envp) == -1) + return (-1); + if (errno == EACCES) + eacces = true; + } + + /* + * We don't often preserve errors encountering during the PATH search, + * so we override it here. ENOENT would be misleading if we found a + * candidate but couldn't access it, but most of the other conditions + * are either terminal or indicate that nothing was there. + */ + if (eacces) + errno = EACCES; + else + errno = ENOENT; + + return (-1); +} + +int +execvP(const char *name, const char *path, char * const argv[]) +{ + return execvPe(name, path, argv, environ); +} + +int +__libc_execvpe(const char *name, char * const argv[], char * const envp[]) +{ + const char *path; + + /* Get the path we're searching. */ + if ((path = getenv("PATH")) == NULL) + path = _PATH_DEFPATH; + + return (execvPe(name, path, argv, envp)); +} + +__weak_reference(__libc_execvpe, execvpe); diff --git a/lib/libc/gen/exect.c b/lib/libc/gen/exect.c new file mode 100644 index 000000000000..e5be7a4d8755 --- /dev/null +++ b/lib/libc/gen/exect.c @@ -0,0 +1,42 @@ +/*- + * Copyright (c) 2018 Ali Mashtizadeh <ali@mashtizadeh.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/ptrace.h> + +#include <errno.h> +#include <unistd.h> + +int +exect(const char *path, char *const argv[], char *const envp[]) +{ + + if (ptrace(PT_TRACE_ME, 0, 0, 0) != 0) { + if (errno != EBUSY) + return (-1); + } + + return (execve(path, argv, envp)); +} diff --git a/lib/libc/gen/fdevname.c b/lib/libc/gen/fdevname.c new file mode 100644 index 000000000000..62e71e98af63 --- /dev/null +++ b/lib/libc/gen/fdevname.c @@ -0,0 +1,54 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/ioctl.h> +#include <stdlib.h> +#include "un-namespace.h" + +char * +fdevname_r(int fd, char *buf, int len) +{ + struct fiodgname_arg fgn; + + fgn.buf = buf; + fgn.len = len; + + if (_ioctl(fd, FIODGNAME, &fgn) == -1) + return (NULL); + return (buf); +} + +char * +fdevname(int fd) +{ + static char buf[SPECNAMELEN + 1]; + + return (fdevname_r(fd, buf, sizeof(buf))); +} diff --git a/lib/libc/gen/fdopendir.c b/lib/libc/gen/fdopendir.c new file mode 100644 index 000000000000..9393cbe28f85 --- /dev/null +++ b/lib/libc/gen/fdopendir.c @@ -0,0 +1,63 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include "un-namespace.h" + +#include "gen-private.h" +#include "telldir.h" + +/* + * Open a directory with existing file descriptor. + */ +DIR * +fdopendir(int fd) +{ + int flags, rc; + + flags = _fcntl(fd, F_GETFD, 0); + if (flags == -1) + return (NULL); + + if ((flags & FD_CLOEXEC) == 0) { + rc = _fcntl(fd, F_SETFD, flags | FD_CLOEXEC); + if (rc == -1) + return (NULL); + } + return (__opendir_common(fd, DTF_HIDEW | DTF_NODUP, true)); +} diff --git a/lib/libc/gen/feature_present.3 b/lib/libc/gen/feature_present.3 new file mode 100644 index 000000000000..3741ea0d3975 --- /dev/null +++ b/lib/libc/gen/feature_present.3 @@ -0,0 +1,70 @@ +.\" Copyright (c) 2008 Yahoo!, Inc. +.\" All rights reserved. +.\" Written by: John Baldwin <jhb@FreeBSD.org> +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the author nor the names of any co-contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 8, 2008 +.Dt FEATURE_PRESENT 3 +.Os +.Sh NAME +.Nm feature_present +.Nd query presence of a kernel feature +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn feature_present "const char *feature" +.Sh DESCRIPTION +The +.Fn feature_present +function provides a method for an application to determine if a specific +kernel feature is present in the currently running kernel. +The +.Fa feature +argument specifies the name of the feature to check. +The +.Fn feature_present +function will return 1 if the specified feature is present, +otherwise it will return 0. +If the +.Fn feature_present +function is not able to determine the presence of +.Fa feature +due to an internal error it will return 0. +.Sh RETURN VALUES +If +.Fa feature +is present then 1 is returned; +otherwise 0 is returned. +.Sh SEE ALSO +.Xr sysconf 3 , +.Xr sysctl 3 +.Sh HISTORY +The +.Fn feature_present +function first appeared in +.Fx 8.0 . diff --git a/lib/libc/gen/feature_present.c b/lib/libc/gen/feature_present.c new file mode 100644 index 000000000000..4c0b41cfb23e --- /dev/null +++ b/lib/libc/gen/feature_present.c @@ -0,0 +1,62 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 2008 Yahoo!, Inc. + * All rights reserved. + * Written by: John Baldwin <jhb@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +/* + * Returns true if the named feature is present in the currently + * running kernel. A feature's presence is indicated by an integer + * sysctl node called kern.feature.<feature> that is non-zero. + */ +int +feature_present(const char *feature) +{ + char *mib; + size_t len; + int i; + + if (asprintf(&mib, "kern.features.%s", feature) < 0) + return (0); + len = sizeof(i); + if (sysctlbyname(mib, &i, &len, NULL, 0) < 0) { + free(mib); + return (0); + } + free(mib); + if (len != sizeof(i)) + return (0); + return (i != 0); +} diff --git a/lib/libc/gen/fmtcheck.3 b/lib/libc/gen/fmtcheck.3 new file mode 100644 index 000000000000..07982f28b296 --- /dev/null +++ b/lib/libc/gen/fmtcheck.3 @@ -0,0 +1,106 @@ +.\" Copyright (c) 2000 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This file was contributed to The NetBSD Foundation by Allen Briggs. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.Dd October 16, 2002 +.Dt FMTCHECK 3 +.Os +.Sh NAME +.Nm fmtcheck +.Nd sanitizes user-supplied +.Xr printf 3 Ns -style +format string +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdio.h +.Ft const char * +.Fn fmtcheck "const char *fmt_suspect" "const char *fmt_default" +.Sh DESCRIPTION +The +.Fn fmtcheck +scans +.Fa fmt_suspect +and +.Fa fmt_default +to determine if +.Fa fmt_suspect +will consume the same argument types as +.Fa fmt_default +and to ensure that +.Fa fmt_suspect +is a valid format string. +.Pp +The +.Xr printf 3 +family of functions cannot verify the types of arguments that they are +passed at run-time. +In some cases, like +.Xr catgets 3 , +it is useful or necessary to use a user-supplied format string with no +guarantee that the format string matches the specified arguments. +.Pp +The +.Fn fmtcheck +was designed to be used in these cases, as in: +.Bd -literal -offset indent +printf(fmtcheck(user_format, standard_format), arg1, arg2); +.Ed +.Pp +In the check, field widths, fillers, precisions, etc.\& are ignored (unless +the field width or precision is an asterisk +.Ql * +instead of a digit string). +Also, any text other than the format specifiers +is completely ignored. +.Sh RETURN VALUES +If +.Fa fmt_suspect +is a valid format and consumes the same argument types as +.Fa fmt_default , +then the +.Fn fmtcheck +will return +.Fa fmt_suspect . +Otherwise, it will return +.Fa fmt_default . +.Sh SEE ALSO +.Xr printf 3 +.Sh BUGS +The +.Fn fmtcheck +function does not recognize positional parameters. +.Sh SECURITY CONSIDERATIONS +Note that the formats may be quite different as long as they accept the +same arguments. +For example, +.Qq Li "%p %o %30s %#llx %-10.*e %n" +is compatible with +.Qq Li "This number %lu %d%% and string %s has %qd numbers and %.*g floats (%n)" . +However, +.Qq Li %o +is not equivalent to +.Qq Li %lx +because +the first requires an integer and the second requires a long. diff --git a/lib/libc/gen/fmtcheck.c b/lib/libc/gen/fmtcheck.c new file mode 100644 index 000000000000..de889ad3421c --- /dev/null +++ b/lib/libc/gen/fmtcheck.c @@ -0,0 +1,325 @@ +/* $NetBSD: fmtcheck.c,v 1.8 2008/04/28 20:22:59 martin Exp $ */ + +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code was contributed to The NetBSD Foundation by Allen Briggs. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +__weak_reference(__fmtcheck, fmtcheck); +const char * __fmtcheck(const char *, const char *); + +enum __e_fmtcheck_types { + FMTCHECK_START, + FMTCHECK_SHORT, + FMTCHECK_INT, + FMTCHECK_WINTT, + FMTCHECK_LONG, + FMTCHECK_QUAD, + FMTCHECK_INTMAXT, + FMTCHECK_PTRDIFFT, + FMTCHECK_SIZET, + FMTCHECK_CHARPOINTER, + FMTCHECK_SHORTPOINTER, + FMTCHECK_INTPOINTER, + FMTCHECK_LONGPOINTER, + FMTCHECK_QUADPOINTER, + FMTCHECK_INTMAXTPOINTER, + FMTCHECK_PTRDIFFTPOINTER, + FMTCHECK_SIZETPOINTER, +#ifndef NO_FLOATING_POINT + FMTCHECK_DOUBLE, + FMTCHECK_LONGDOUBLE, +#endif + FMTCHECK_STRING, + FMTCHECK_WSTRING, + FMTCHECK_WIDTH, + FMTCHECK_PRECISION, + FMTCHECK_DONE, + FMTCHECK_UNKNOWN +}; +typedef enum __e_fmtcheck_types EFT; + +enum e_modifier { + MOD_NONE, + MOD_CHAR, + MOD_SHORT, + MOD_LONG, + MOD_QUAD, + MOD_INTMAXT, + MOD_LONGDOUBLE, + MOD_PTRDIFFT, + MOD_SIZET, +}; + +#define RETURN(pf,f,r) do { \ + *(pf) = (f); \ + return r; \ + } /*NOTREACHED*/ /*CONSTCOND*/ while (0) + +static EFT +get_next_format_from_precision(const char **pf) +{ + enum e_modifier modifier; + const char *f; + + f = *pf; + switch (*f) { + case 'h': + f++; + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + if (*f == 'h') { + f++; + modifier = MOD_CHAR; + } else { + modifier = MOD_SHORT; + } + break; + case 'j': + f++; + modifier = MOD_INTMAXT; + break; + case 'l': + f++; + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + if (*f == 'l') { + f++; + modifier = MOD_QUAD; + } else { + modifier = MOD_LONG; + } + break; + case 'q': + f++; + modifier = MOD_QUAD; + break; + case 't': + f++; + modifier = MOD_PTRDIFFT; + break; + case 'z': + f++; + modifier = MOD_SIZET; + break; + case 'L': + f++; + modifier = MOD_LONGDOUBLE; + break; + default: + modifier = MOD_NONE; + break; + } + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + if (strchr("diouxX", *f)) { + switch (modifier) { + case MOD_LONG: + RETURN(pf,f,FMTCHECK_LONG); + case MOD_QUAD: + RETURN(pf,f,FMTCHECK_QUAD); + case MOD_INTMAXT: + RETURN(pf,f,FMTCHECK_INTMAXT); + case MOD_PTRDIFFT: + RETURN(pf,f,FMTCHECK_PTRDIFFT); + case MOD_SIZET: + RETURN(pf,f,FMTCHECK_SIZET); + case MOD_CHAR: + case MOD_SHORT: + case MOD_NONE: + RETURN(pf,f,FMTCHECK_INT); + default: + RETURN(pf,f,FMTCHECK_UNKNOWN); + } + } + if (*f == 'n') { + switch (modifier) { + case MOD_CHAR: + RETURN(pf,f,FMTCHECK_CHARPOINTER); + case MOD_SHORT: + RETURN(pf,f,FMTCHECK_SHORTPOINTER); + case MOD_LONG: + RETURN(pf,f,FMTCHECK_LONGPOINTER); + case MOD_QUAD: + RETURN(pf,f,FMTCHECK_QUADPOINTER); + case MOD_INTMAXT: + RETURN(pf,f,FMTCHECK_INTMAXTPOINTER); + case MOD_PTRDIFFT: + RETURN(pf,f,FMTCHECK_PTRDIFFTPOINTER); + case MOD_SIZET: + RETURN(pf,f,FMTCHECK_SIZETPOINTER); + case MOD_NONE: + RETURN(pf,f,FMTCHECK_INTPOINTER); + default: + RETURN(pf,f,FMTCHECK_UNKNOWN); + } + } + if (strchr("DOU", *f)) { + if (modifier != MOD_NONE) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_LONG); + } +#ifndef NO_FLOATING_POINT + if (strchr("aAeEfFgG", *f)) { + switch (modifier) { + case MOD_LONGDOUBLE: + RETURN(pf,f,FMTCHECK_LONGDOUBLE); + case MOD_LONG: + case MOD_NONE: + RETURN(pf,f,FMTCHECK_DOUBLE); + default: + RETURN(pf,f,FMTCHECK_UNKNOWN); + } + } +#endif + if (*f == 'c') { + switch (modifier) { + case MOD_LONG: + RETURN(pf,f,FMTCHECK_WINTT); + case MOD_NONE: + RETURN(pf,f,FMTCHECK_INT); + default: + RETURN(pf,f,FMTCHECK_UNKNOWN); + } + } + if (*f == 'C') { + if (modifier != MOD_NONE) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_WINTT); + } + if (*f == 's') { + switch (modifier) { + case MOD_LONG: + RETURN(pf,f,FMTCHECK_WSTRING); + case MOD_NONE: + RETURN(pf,f,FMTCHECK_STRING); + default: + RETURN(pf,f,FMTCHECK_UNKNOWN); + } + } + if (*f == 'S') { + if (modifier != MOD_NONE) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_WSTRING); + } + if (*f == 'p') { + if (modifier != MOD_NONE) + RETURN(pf,f,FMTCHECK_UNKNOWN); + RETURN(pf,f,FMTCHECK_LONG); + } + RETURN(pf,f,FMTCHECK_UNKNOWN); + /*NOTREACHED*/ +} + +static EFT +get_next_format_from_width(const char **pf) +{ + const char *f; + + f = *pf; + if (*f == '.') { + f++; + if (*f == '*') { + RETURN(pf,f,FMTCHECK_PRECISION); + } + /* eat any precision (empty is allowed) */ + while (isdigit(*f)) f++; + if (!*f) RETURN(pf,f,FMTCHECK_UNKNOWN); + } + RETURN(pf,f,get_next_format_from_precision(pf)); + /*NOTREACHED*/ +} + +static EFT +get_next_format(const char **pf, EFT eft) +{ + int infmt; + const char *f; + + if (eft == FMTCHECK_WIDTH) { + (*pf)++; + return get_next_format_from_width(pf); + } else if (eft == FMTCHECK_PRECISION) { + (*pf)++; + return get_next_format_from_precision(pf); + } + + f = *pf; + infmt = 0; + while (!infmt) { + f = strchr(f, '%'); + if (f == NULL) + RETURN(pf,f,FMTCHECK_DONE); + f++; + if (!*f) + RETURN(pf,f,FMTCHECK_UNKNOWN); + if (*f != '%') + infmt = 1; + else + f++; + } + + /* Eat any of the flags */ + while (*f && (strchr("#'0- +", *f))) + f++; + + if (*f == '*') { + RETURN(pf,f,FMTCHECK_WIDTH); + } + /* eat any width */ + while (isdigit(*f)) f++; + if (!*f) { + RETURN(pf,f,FMTCHECK_UNKNOWN); + } + + RETURN(pf,f,get_next_format_from_width(pf)); + /*NOTREACHED*/ +} + +const char * +__fmtcheck(const char *f1, const char *f2) +{ + const char *f1p, *f2p; + EFT f1t, f2t; + + if (!f1) return f2; + + f1p = f1; + f1t = FMTCHECK_START; + f2p = f2; + f2t = FMTCHECK_START; + while ((f1t = get_next_format(&f1p, f1t)) != FMTCHECK_DONE) { + if (f1t == FMTCHECK_UNKNOWN) + return f2; + f2t = get_next_format(&f2p, f2t); + if (f1t != f2t) + return f2; + } + return f1; +} diff --git a/lib/libc/gen/fmtmsg.3 b/lib/libc/gen/fmtmsg.3 new file mode 100644 index 000000000000..e50ab317e1aa --- /dev/null +++ b/lib/libc/gen/fmtmsg.3 @@ -0,0 +1,258 @@ +.\" +.\" Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd August 5, 2002 +.Dt FMTMSG 3 +.Os +.Sh NAME +.Nm fmtmsg +.Nd display a detailed diagnostic message +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In fmtmsg.h +.Ft int +.Fo fmtmsg +.Fa "long classification" "const char *label" "int severity" +.Fa "const char *text" "const char *action" "const char *tag" +.Fc +.Sh DESCRIPTION +The +.Fn fmtmsg +function displays a detailed diagnostic message, based on +the supplied arguments, to +.Dv stderr +and/or the system console. +.Pp +The +.Fa classification +argument is the bitwise inclusive +.Tn OR +of zero or one of the manifest constants from +each of the classification groups below. +The Output classification group is an exception since both +.Dv MM_PRINT +and +.Dv MM_CONSOLE +may be specified. +.Bl -tag -width indent +.It Output +.Bl -tag -width ".Dv MM_CONSOLE" +.It Dv MM_PRINT +Output should take place on +.Dv stderr . +.It Dv MM_CONSOLE +Output should take place on the system console. +.El +.It "Source of Condition (Major)" +.Bl -tag -width ".Dv MM_CONSOLE" +.It Dv MM_HARD +The source of the condition is hardware related. +.It Dv MM_SOFT +The source of the condition is software related. +.It Dv MM_FIRM +The source of the condition is firmware related. +.El +.It "Source of Condition (Minor)" +.Bl -tag -width ".Dv MM_CONSOLE" +.It Dv MM_APPL +The condition was detected at the application level. +.It Dv MM_UTIL +The condition was detected at the utility level. +.It Dv MM_OPSYS +The condition was detected at the operating system level. +.El +.It Status +.Bl -tag -width ".Dv MM_CONSOLE" +.It Dv MM_RECOVER +The application can recover from the condition. +.It Dv MM_NRECOV +The application is unable to recover from the condition. +.El +.El +.Pp +Alternatively, the +.Dv MM_NULLMC +manifest constant may be used to specify no classification. +.Pp +The +.Fa label +argument indicates the source of the message. +It is made up of two fields separated by a colon +.Pq Ql \&: . +The first field can be up to 10 bytes, +and the second field can be up to 14 bytes. +The +.Dv MM_NULLLBL +manifest constant may be used to specify no label. +.Pp +The +.Fa severity +argument identifies the importance of the condition. +One of the following manifest constants should be used for this argument. +.Bl -tag -offset indent -width ".Dv MM_WARNING" +.It Dv MM_HALT +The application has confronted a serious fault and is halting. +.It Dv MM_ERROR +The application has detected a fault. +.It Dv MM_WARNING +The application has detected an unusual condition, +that could be indicative of a problem. +.It Dv MM_INFO +The application is providing information about a non-error condition. +.It Dv MM_NOSEV +No severity level supplied. +.El +.Pp +The +.Fa text +argument details the error condition that caused the message. +There is no limit on the size of this character string. +The +.Dv MM_NULLTXT +manifest constant may be used to specify no text. +.Pp +The +.Fa action +argument details how the error-recovery process should begin. +Upon output, +.Fn fmtmsg +will prefix +.Qq Li "TO FIX:" +to the beginning of the +.Fa action +argument. +The +.Dv MM_NULLACT +manifest constant may be used to specify no action. +.Pp +The +.Fa tag +argument should reference online documentation for the message. +This usually includes the +.Fa label +and a unique identifying number. +An example tag is +.Qq Li BSD:ls:168 . +The +.Dv MM_NULLTAG +manifest constant may be used to specify no tag. +.Sh RETURN VALUES +The +.Fn fmtmsg +function returns +.Dv MM_OK +upon success, +.Dv MM_NOMSG +to indicate output to +.Dv stderr +failed, +.Dv MM_NOCON +to indicate output to the system console failed, or +.Dv MM_NOTOK +to indicate output to +.Dv stderr +and the system console failed. +.Sh ENVIRONMENT +The +.Ev MSGVERB +(message verbosity) +environment variable specifies which arguments to +.Fn fmtmsg +will be output to +.Dv stderr , +and in which order. +.Ev MSGVERB +should be a colon +.Pq Ql \&: +separated list of identifiers. +Valid identifiers include: +.Li label , severity , text , action , +and +.Li tag . +If invalid identifiers are specified or incorrectly separated, +the default message verbosity and ordering will be used. +The default ordering is equivalent to a +.Ev MSGVERB +with a value of +.Qq Li label:severity:text:action:tag . +.Sh EXAMPLES +The code: +.Bd -literal -offset indent +fmtmsg(MM_UTIL | MM_PRINT, "BSD:ls", MM_ERROR, + "illegal option -- z", "refer to manual", "BSD:ls:001"); +.Ed +.Pp +will output: +.Bd -literal -offset indent +BSD:ls: ERROR: illegal option -- z +TO FIX: refer to manual BSD:ls:001 +.Ed +.Pp +to +.Dv stderr . +.Pp +The same code, with +.Ev MSGVERB +set to +.Qq Li "text:severity:action:tag" , +produces: +.Bd -literal -offset indent +illegal option -- z: ERROR +TO FIX: refer to manual BSD:ls:001 +.Ed +.Sh SEE ALSO +.Xr err 3 , +.Xr exit 3 , +.Xr strerror 3 +.Sh STANDARDS +The +.Fn fmtmsg +function conforms to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn fmtmsg +function first appeared in +.Fx 5.0 . +.Sh BUGS +Specifying +.Dv MM_NULLMC +for the +.Fa classification +argument makes little sense, since without an output specified, +.Fn fmtmsg +is unable to do anything useful. +.Pp +In order for +.Fn fmtmsg +to output to the system console, the effective +user must have appropriate permission to write to +.Pa /dev/console . +This means that on most systems +.Fn fmtmsg +will return +.Dv MM_NOCON +unless the effective user is root. diff --git a/lib/libc/gen/fmtmsg.c b/lib/libc/gen/fmtmsg.c new file mode 100644 index 000000000000..9edeee4405ce --- /dev/null +++ b/lib/libc/gen/fmtmsg.c @@ -0,0 +1,219 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2002 Mike Barcroft <mike@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <fmtmsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* Default value for MSGVERB. */ +#define DFLT_MSGVERB "label:severity:text:action:tag" + +/* Maximum valid size for a MSGVERB. */ +#define MAX_MSGVERB sizeof(DFLT_MSGVERB) + +static char *printfmt(char *, long, const char *, int, const char *, + const char *, const char *); +static char *nextcomp(const char *); +static const char + *sevinfo(int); +static int validmsgverb(const char *); + +int +fmtmsg(long class, const char *label, int sev, const char *text, + const char *action, const char *tag) +{ + FILE *fp; + char *env, *msgverb, *output; + + if (class & MM_PRINT) { + if ((env = getenv("MSGVERB")) != NULL && *env != '\0' && + strlen(env) <= strlen(DFLT_MSGVERB)) { + if ((msgverb = strdup(env)) == NULL) + return (MM_NOTOK); + else if (validmsgverb(msgverb) == 0) { + free(msgverb); + goto def; + } + } else { +def: + if ((msgverb = strdup(DFLT_MSGVERB)) == NULL) + return (MM_NOTOK); + } + output = printfmt(msgverb, class, label, sev, text, action, + tag); + if (output == NULL) { + free(msgverb); + return (MM_NOTOK); + } + if (*output != '\0') + fprintf(stderr, "%s", output); + free(msgverb); + free(output); + } + if (class & MM_CONSOLE) { + output = printfmt(DFLT_MSGVERB, class, label, sev, text, + action, tag); + if (output == NULL) + return (MM_NOCON); + if (*output != '\0') { + if ((fp = fopen("/dev/console", "ae")) == NULL) { + free(output); + return (MM_NOCON); + } + fprintf(fp, "%s", output); + fclose(fp); + } + free(output); + } + return (MM_OK); +} + +#define INSERT_COLON \ + if (*output != '\0') \ + strlcat(output, ": ", size) +#define INSERT_NEWLINE \ + if (*output != '\0') \ + strlcat(output, "\n", size) +#define INSERT_SPACE \ + if (*output != '\0') \ + strlcat(output, " ", size) + +/* + * Returns NULL on memory allocation failure, otherwise returns a pointer to + * a newly malloc()'d output buffer. + */ +static char * +printfmt(char *msgverb, long class, const char *label, int sev, + const char *text, const char *act, const char *tag) +{ + size_t size; + char *comp, *output; + const char *sevname; + + size = 32; + if (label != MM_NULLLBL) + size += strlen(label); + if ((sevname = sevinfo(sev)) != NULL) + size += strlen(sevname); + if (text != MM_NULLTXT) + size += strlen(text); + if (act != MM_NULLACT) + size += strlen(act); + if (tag != MM_NULLTAG) + size += strlen(tag); + + if ((output = malloc(size)) == NULL) + return (NULL); + *output = '\0'; + while ((comp = nextcomp(msgverb)) != NULL) { + if (strcmp(comp, "label") == 0 && label != MM_NULLLBL) { + INSERT_COLON; + strlcat(output, label, size); + } else if (strcmp(comp, "severity") == 0 && sevname != NULL) { + INSERT_COLON; + strlcat(output, sevinfo(sev), size); + } else if (strcmp(comp, "text") == 0 && text != MM_NULLTXT) { + INSERT_COLON; + strlcat(output, text, size); + } else if (strcmp(comp, "action") == 0 && act != MM_NULLACT) { + INSERT_NEWLINE; + strlcat(output, "TO FIX: ", size); + strlcat(output, act, size); + } else if (strcmp(comp, "tag") == 0 && tag != MM_NULLTAG) { + INSERT_SPACE; + strlcat(output, tag, size); + } + } + INSERT_NEWLINE; + return (output); +} + +/* + * Returns a component of a colon delimited string. NULL is returned to + * indicate that there are no remaining components. This function must be + * called until it returns NULL in order for the local state to be cleared. + */ +static char * +nextcomp(const char *msgverb) +{ + static char lmsgverb[MAX_MSGVERB], *state; + char *retval; + + if (*lmsgverb == '\0') { + strlcpy(lmsgverb, msgverb, sizeof(lmsgverb)); + retval = strtok_r(lmsgverb, ":", &state); + } else { + retval = strtok_r(NULL, ":", &state); + } + if (retval == NULL) + *lmsgverb = '\0'; + return (retval); +} + +static const char * +sevinfo(int sev) +{ + + switch (sev) { + case MM_HALT: + return ("HALT"); + case MM_ERROR: + return ("ERROR"); + case MM_WARNING: + return ("WARNING"); + case MM_INFO: + return ("INFO"); + default: + return (NULL); + } +} + +/* + * Returns 1 if the msgverb list is valid, otherwise 0. + */ +static int +validmsgverb(const char *msgverb) +{ + const char *validlist = "label\0severity\0text\0action\0tag\0"; + char *msgcomp; + size_t len1, len2; + const char *p; + int equality; + + equality = 0; + while ((msgcomp = nextcomp(msgverb)) != NULL) { + equality--; + len1 = strlen(msgcomp); + for (p = validlist; (len2 = strlen(p)) != 0; p += len2 + 1) { + if (len1 == len2 && memcmp(msgcomp, p, len1) == 0) + equality++; + } + } + return (!equality); +} diff --git a/lib/libc/gen/fnmatch.3 b/lib/libc/gen/fnmatch.3 new file mode 100644 index 000000000000..7f020fec58e3 --- /dev/null +++ b/lib/libc/gen/fnmatch.3 @@ -0,0 +1,148 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Guido van Rossum. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 7, 2025 +.Dt FNMATCH 3 +.Os +.Sh NAME +.Nm fnmatch +.Nd test whether a filename or pathname matches a shell-style pattern +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In fnmatch.h +.Ft int +.Fn fnmatch "const char *pattern" "const char *string" "int flags" +.Sh DESCRIPTION +The +.Fn fnmatch +function +matches patterns according to the rules used by the shell. +It checks the string specified by the +.Fa string +argument to see if it matches the pattern specified by the +.Fa pattern +argument. +.Pp +The +.Fa flags +argument modifies the interpretation of +.Fa pattern +and +.Fa string . +The value of +.Fa flags +is the bitwise inclusive +.Tn OR +of any of the following +constants, which are defined in the include file +.In fnmatch.h . +.Bl -tag -width FNM_PATHNAME +.It Dv FNM_NOESCAPE +Normally, every occurrence of a backslash +.Pq Ql \e +followed by a character in +.Fa pattern +is replaced by that character. +This is done to negate any special meaning for the character. +If the +.Dv FNM_NOESCAPE +flag is set, a backslash character is treated as an ordinary character. +.It Dv FNM_PATHNAME +Slash characters in +.Fa string +must be explicitly matched by slashes in +.Fa pattern . +If this flag is not set, then slashes are treated as regular characters. +.It Dv FNM_PERIOD +Leading periods in +.Fa string +must be explicitly matched by periods in +.Fa pattern . +If this flag is not set, then leading periods are treated as regular +characters. +The definition of +.Dq leading +is related to the specification of +.Dv FNM_PATHNAME . +A period is always +.Dq leading +if it is the first character in +.Fa string . +Additionally, if +.Dv FNM_PATHNAME +is set, +a period is +leading +if it immediately follows a slash. +.It Dv FNM_LEADING_DIR +Ignore +.Dq Li /* +rest after successful +.Fa pattern +matching. +.It Dv FNM_CASEFOLD +Ignore case distinctions in both the +.Fa pattern +and the +.Fa string . +.El +.Sh RETURN VALUES +The +.Fn fnmatch +function returns zero if +.Fa string +matches the pattern specified by +.Fa pattern , +otherwise, it returns the value +.Dv FNM_NOMATCH . +.Sh SEE ALSO +.Xr sh 1 , +.Xr glob 3 , +.Xr regex 3 +.Sh STANDARDS +The current implementation of the +.Fn fnmatch +function is expected to conform to +.St -p1003.2 . +.Sh HISTORY +A predecessor to +.Fn fnmatch , +.Fn gmatch , +first appeared in the Programmer's Workbench (PWB/UNIX). +The +.Fn fnmatch +function first appeared in +.Bx 4.4 . +.Sh BUGS +The pattern +.Ql * +matches the empty string, even if +.Dv FNM_PATHNAME +is specified. diff --git a/lib/libc/gen/fnmatch.c b/lib/libc/gen/fnmatch.c new file mode 100644 index 000000000000..1c583a9d23e2 --- /dev/null +++ b/lib/libc/gen/fnmatch.c @@ -0,0 +1,491 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. + * Compares a filename or pathname to a pattern. + */ + +/* + * Some notes on multibyte character support: + * 1. Patterns with illegal byte sequences match nothing. + * 2. Illegal byte sequences in the "string" argument are handled by treating + * them as single-byte characters with a value of the first byte of the + * sequence cast to wchar_t. + * 3. Multibyte conversion state objects (mbstate_t) are passed around and + * used for most, but not all, conversions. Further work will be required + * to support state-dependent encodings. + */ + +#include <fnmatch.h> +#include <limits.h> +#include <string.h> +#include <wchar.h> +#include <wctype.h> + +#include "collate.h" + +#define EOS '\0' + +#define RANGE_MATCH 1 +#define RANGE_NOMATCH 0 +#define RANGE_ERROR (-1) + +static int rangematch(const char *, wchar_t, const char *, int, char **, + char **, mbstate_t *, mbstate_t *); +static int fnmatch1(const char *, const char *, const char *, int, mbstate_t, + mbstate_t); + +int +fnmatch(const char *pattern, const char *string, int flags) +{ + static const mbstate_t initial; + + return (fnmatch1(pattern, string, string, flags, initial, initial)); +} + +static int +fnmatch1(const char *pattern, const char *string, const char *stringstart, + int flags, mbstate_t patmbs, mbstate_t strmbs) +{ + const char *bt_pattern, *bt_string; + mbstate_t bt_patmbs, bt_strmbs; + char *newp, *news; + char c; + wchar_t pc, sc; + size_t pclen, sclen; + + bt_pattern = bt_string = NULL; + for (;;) { + pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, &patmbs); + if (pclen == (size_t)-1 || pclen == (size_t)-2) + return (FNM_NOMATCH); + pattern += pclen; + sclen = mbrtowc(&sc, string, MB_LEN_MAX, &strmbs); + if (sclen == (size_t)-1 || sclen == (size_t)-2) { + sc = (unsigned char)*string; + sclen = 1; + memset(&strmbs, 0, sizeof(strmbs)); + } + switch (pc) { + case EOS: + if ((flags & FNM_LEADING_DIR) && sc == '/') + return (0); + if (sc == EOS) + return (0); + goto backtrack; + case '?': + if (sc == EOS) + return (FNM_NOMATCH); + if (sc == '/' && (flags & FNM_PATHNAME)) + goto backtrack; + if (sc == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + goto backtrack; + string += sclen; + break; + case '*': + c = *pattern; + /* Collapse multiple stars. */ + while (c == '*') + c = *++pattern; + + if (sc == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + goto backtrack; + + /* Optimize for pattern with * at end or before /. */ + if (c == EOS) + if (flags & FNM_PATHNAME) + return ((flags & FNM_LEADING_DIR) || + strchr(string, '/') == NULL ? + 0 : FNM_NOMATCH); + else + return (0); + else if (c == '/' && flags & FNM_PATHNAME) { + if ((string = strchr(string, '/')) == NULL) + return (FNM_NOMATCH); + break; + } + + /* + * First try the shortest match for the '*' that + * could work. We can forget any earlier '*' since + * there is no way having it match more characters + * can help us, given that we are already here. + */ + bt_pattern = pattern; + bt_patmbs = patmbs; + bt_string = string; + bt_strmbs = strmbs; + break; + case '[': + if (sc == EOS) + return (FNM_NOMATCH); + if (sc == '/' && (flags & FNM_PATHNAME)) + goto backtrack; + if (sc == '.' && (flags & FNM_PERIOD) && + (string == stringstart || + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) + goto backtrack; + + switch (rangematch(pattern, sc, string + sclen, flags, + &newp, &news, &patmbs, &strmbs)) { + case RANGE_ERROR: + goto norm; + case RANGE_MATCH: + pattern = newp; + string = news; + break; + case RANGE_NOMATCH: + goto backtrack; + } + break; + case '\\': + if (!(flags & FNM_NOESCAPE)) { + pclen = mbrtowc(&pc, pattern, MB_LEN_MAX, + &patmbs); + if (pclen == 0 || pclen == (size_t)-1 || + pclen == (size_t)-2) + return (FNM_NOMATCH); + pattern += pclen; + } + /* FALLTHROUGH */ + default: + norm: + string += sclen; + if (pc == sc) + ; + else if ((flags & FNM_CASEFOLD) && + (towlower(pc) == towlower(sc))) + ; + else { + backtrack: + /* + * If we have a mismatch (other than hitting + * the end of the string), go back to the last + * '*' seen and have it match one additional + * character. + */ + if (bt_pattern == NULL) + return (FNM_NOMATCH); + sclen = mbrtowc(&sc, bt_string, MB_LEN_MAX, + &bt_strmbs); + if (sclen == (size_t)-1 || + sclen == (size_t)-2) { + sc = (unsigned char)*bt_string; + sclen = 1; + memset(&bt_strmbs, 0, + sizeof(bt_strmbs)); + } + if (sc == EOS) + return (FNM_NOMATCH); + if (sc == '/' && flags & FNM_PATHNAME) + return (FNM_NOMATCH); + bt_string += sclen; + pattern = bt_pattern; + patmbs = bt_patmbs; + string = bt_string; + strmbs = bt_strmbs; + } + break; + } + } + /* NOTREACHED */ +} + +static int +rangematch(const char *pattern, wchar_t test, const char *string, int flags, + char **newp, char **news, mbstate_t *patmbs, mbstate_t *strmbs) +{ + int negate, ok; + wchar_t c, c2; + size_t pclen; + const char *origpat; + struct xlocale_collate *table = + (struct xlocale_collate *)__get_locale()->components[XLC_COLLATE]; + wchar_t buf[COLLATE_STR_LEN]; /* STR_LEN defined in collate.h */ + const char *cp, *savestring; + int special; + mbstate_t save; + size_t sclen, len; + + /* + * A bracket expression starting with an unquoted circumflex + * character produces unspecified results (IEEE 1003.2-1992, + * 3.13.2). This implementation treats it like '!', for + * consistency with the regular expression syntax. + * J.T. Conklin (conklin@ngai.kaleida.com) + */ + if ((negate = (*pattern == '!' || *pattern == '^'))) + ++pattern; + + if (flags & FNM_CASEFOLD) + test = towlower(test); + + /* + * A right bracket shall lose its special meaning and represent + * itself in a bracket expression if it occurs first in the list. + * -- POSIX.2 2.8.3.2 + */ + ok = 0; + origpat = pattern; + for (;;) { + c = 0; + if (*pattern == ']' && pattern > origpat) { + break; + } else if (*pattern == '\0') { + return (RANGE_ERROR); + } else if (*pattern == '/' && (flags & FNM_PATHNAME)) { + return (RANGE_NOMATCH); + } else if (*pattern == '\\' && !(flags & FNM_NOESCAPE)) { + pattern++; + } else if (*pattern == '[' && + ((special = *(pattern + 1)) == '.' || + special == '=' || special == ':')) { + cp = (pattern += 2); + while ((cp = strchr(cp, special))) { + if (*(cp + 1) == ']') + break; + cp++; + } + if (!cp) + return (RANGE_ERROR); + if (special == '.') { +treat_like_collating_symbol: + len = __collate_collating_symbol(buf, + COLLATE_STR_LEN, pattern, + cp - pattern, patmbs); + if (len == (size_t)-1 || len == 0) + return (RANGE_ERROR); + pattern = cp + 2; + if (len > 1) { + wchar_t *wp, sc; + + /* + * No multi-character collation + * symbols as start of range. + */ + if (*(cp + 2) == '-' && + *(cp + 3) != EOS && + *(cp + 3) != ']') + return (RANGE_ERROR); + wp = buf; + if (test != *wp++) + continue; + if (len == 1) { + ok = 1; + break; + } + memcpy(&save, strmbs, sizeof(save)); + savestring = string; + while (--len > 0) { + sclen = mbrtowc(&sc, string, + MB_LEN_MAX, strmbs); + if (sclen == (size_t)-1 || + sclen == (size_t)-2) { + sc = (unsigned char)*string; + sclen = 1; + memset(&strmbs, 0, + sizeof(strmbs)); + } + if (sc != *wp++) { + memcpy(strmbs, &save, + sizeof(save)); + string = savestring; + break; + } + string += sclen; + } + if (len == 0) { + ok = 1; + break; + } + continue; /* no match */ + } + c = *buf; + } else if (special == '=') { + int ec; + memcpy(&save, patmbs, sizeof(save)); + ec = __collate_equiv_class(pattern, + cp - pattern, patmbs); + if (ec < 0) + return (RANGE_ERROR); + if (ec == 0) { + memcpy(patmbs, &save, sizeof(save)); + goto treat_like_collating_symbol; + } + pattern = cp + 2; + /* no equivalence classes as start of range */ + if (*(cp + 2) == '-' && *(cp + 3) != EOS && + *(cp + 3) != ']') + return (RANGE_ERROR); + len = __collate_equiv_match(ec, NULL, 0, test, + string, strlen(string), strmbs, &sclen); + if (len < 0) + return (RANGE_ERROR); + if (len > 0) { + ok = 1; + string += sclen; + break; + } + continue; + } else { /* special == ':' */ + wctype_t charclass; + char name[CHARCLASS_NAME_MAX + 1]; + /* no character classes as start of range */ + if (*(cp + 2) == '-' && *(cp + 3) != EOS && + *(cp + 3) != ']') + return (RANGE_ERROR); + /* assume character class names are ascii */ + if (cp - pattern > CHARCLASS_NAME_MAX) + return (RANGE_ERROR); + strlcpy(name, pattern, cp - pattern + 1); + pattern = cp + 2; + if ((charclass = wctype(name)) == 0) + return (RANGE_ERROR); + if (iswctype(test, charclass)) { + ok = 1; + break; + } + continue; + } + } + if (!c) { + pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs); + if (pclen == (size_t)-1 || pclen == (size_t)-2) + return (RANGE_NOMATCH); + pattern += pclen; + } + if (flags & FNM_CASEFOLD) + c = towlower(c); + + if (*pattern == '-' && *(pattern + 1) != EOS && + *(pattern + 1) != ']') { + if (*++pattern == '\\' && !(flags & FNM_NOESCAPE)) + if (*pattern != EOS) + pattern++; + pclen = mbrtowc(&c2, pattern, MB_LEN_MAX, patmbs); + if (pclen == (size_t)-1 || pclen == (size_t)-2) + return (RANGE_NOMATCH); + pattern += pclen; + if (c2 == EOS) + return (RANGE_ERROR); + + if ((c2 == '[' && (special = *pattern) == '.') || + special == '=' || special == ':') { + + /* + * No equivalence classes or character + * classes as end of range. + */ + if (special == '=' || special == ':') + return (RANGE_ERROR); + cp = ++pattern; + while ((cp = strchr(cp, special))) { + if (*(cp + 1) == ']') + break; + cp++; + } + if (!cp) + return (RANGE_ERROR); + len = __collate_collating_symbol(buf, + COLLATE_STR_LEN, pattern, + cp - pattern, patmbs); + + /* + * No multi-character collation symbols + * as end of range. + */ + if (len != 1) + return (RANGE_ERROR); + pattern = cp + 2; + c2 = *buf; + } + + if (flags & FNM_CASEFOLD) + c2 = towlower(c2); + + if (table->__collate_load_error ? + c <= test && test <= c2 : + __wcollate_range_cmp(c, test) <= 0 + && __wcollate_range_cmp(test, c2) <= 0 + ) { + ok = 1; + break; + } + } else if (c == test) { + ok = 1; + break; + } + } + + /* go to end of bracket expression */ + special = 0; + while (*pattern != ']') { + if (*pattern == 0) + return (RANGE_ERROR); + if (*pattern == special) { + if (*++pattern == ']') { + special = 0; + pattern++; + } + continue; + } + if (!special && *pattern == '[') { + special = *++pattern; + if (special != '.' && special != '=' && special != ':') + special = 0; + else + pattern++; + continue; + } + pclen = mbrtowc(&c, pattern, MB_LEN_MAX, patmbs); + if (pclen == (size_t)-1 || pclen == (size_t)-2) + return (RANGE_NOMATCH); + pattern += pclen; + } + + *newp = (char *)++pattern; + *news = (char *)string; + + return (ok == negate ? RANGE_NOMATCH : RANGE_MATCH); +} diff --git a/lib/libc/gen/fpclassify.3 b/lib/libc/gen/fpclassify.3 new file mode 100644 index 000000000000..5a5228463b3c --- /dev/null +++ b/lib/libc/gen/fpclassify.3 @@ -0,0 +1,131 @@ +.\" Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 26, 2005 +.Dt FPCLASSIFY 3 +.Os +.Sh NAME +.Nm fpclassify , isfinite , isinf , isnan , isnormal +.Nd "classify a floating-point number" +.Sh LIBRARY +.Lb libm +.Sh SYNOPSIS +.In math.h +.Ft int +.Fn fpclassify "real-floating x" +.Ft int +.Fn isfinite "real-floating x" +.Ft int +.Fn isinf "real-floating x" +.Ft int +.Fn isnan "real-floating x" +.Ft int +.Fn isnormal "real-floating x" +.Sh DESCRIPTION +The +.Fn fpclassify +macro takes an argument of +.Fa x +and returns one of the following manifest constants. +.Bl -tag -width ".Dv FP_SUBNORMAL" +.It Dv FP_INFINITE +Indicates that +.Fa x +is an infinite number. +.It Dv FP_NAN +Indicates that +.Fa x +is not a number (NaN). +.It Dv FP_NORMAL +Indicates that +.Fa x +is a normalized number. +.It Dv FP_SUBNORMAL +Indicates that +.Fa x +is a denormalized number. +.It Dv FP_ZERO +Indicates that +.Fa x +is zero (0 or \-0). +.El +.Pp +The +.Fn isfinite +macro returns a non-zero value if and only if its argument has +a finite (zero, subnormal, or normal) value. +The +.Fn isinf , +.Fn isnan , +and +.Fn isnormal +macros return non-zero if and only if +.Fa x +is an infinity, NaN, +or a non-zero normalized number, respectively. +.Pp +The symbol +.Fn isnanf +is provided as an alias to +.Fn isnan +for compatibility, and its use is deprecated. +Similarly, +.Fn finite +and +.Fn finitef +are deprecated versions of +.Fn isfinite . +.Sh SEE ALSO +.Xr isgreater 3 , +.Xr math 3 , +.Xr signbit 3 +.Sh STANDARDS +The +.Fn fpclassify , +.Fn isfinite , +.Fn isinf , +.Fn isnan , +and +.Fn isnormal +macros conform to +.St -isoC-99 . +.Sh HISTORY +The +.Fn fpclassify , +.Fn isfinite , +.Fn isinf , +.Fn isnan , +and +.Fn isnormal +macros were added in +.Fx 5.1 . +.Bx 3 +introduced +.Fn isinf +and +.Fn isnan +functions, which accepted +.Vt double +arguments; these have been superseded by the macros +described above. diff --git a/lib/libc/gen/fpclassify.c b/lib/libc/gen/fpclassify.c new file mode 100644 index 000000000000..876cb253a742 --- /dev/null +++ b/lib/libc/gen/fpclassify.c @@ -0,0 +1,103 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2003 Mike Barcroft <mike@FreeBSD.org> + * Copyright (c) 2002, 2003 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/endian.h> + +#include <machine/float.h> + +#include <math.h> +#include <stdint.h> + +#include "fpmath.h" + +int +__fpclassifyf(float f) +{ + union IEEEf2bits u; + + u.f = f; + if (u.bits.exp == 0) { + if (u.bits.man == 0) + return (FP_ZERO); + return (FP_SUBNORMAL); + } + if (u.bits.exp == 255) { + if (u.bits.man == 0) + return (FP_INFINITE); + return (FP_NAN); + } + return (FP_NORMAL); +} + +int +__fpclassifyd(double d) +{ + union IEEEd2bits u; + + u.d = d; + if (u.bits.exp == 0) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_ZERO); + return (FP_SUBNORMAL); + } + if (u.bits.exp == 2047) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_INFINITE); + return (FP_NAN); + } + return (FP_NORMAL); +} + +int +__fpclassifyl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + if (u.bits.exp == 0) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_ZERO); + return (FP_SUBNORMAL); + } + mask_nbit_l(u); /* Mask normalization bit if applicable. */ +#if LDBL_MANT_DIG == 53 + if (u.bits.exp == 2047) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_INFINITE); + return (FP_NAN); + } +#else + if (u.bits.exp == 32767) { + if ((u.bits.manl | u.bits.manh) == 0) + return (FP_INFINITE); + return (FP_NAN); + } +#endif + return (FP_NORMAL); +} diff --git a/lib/libc/gen/frexp.3 b/lib/libc/gen/frexp.3 new file mode 100644 index 000000000000..1424ac888ad6 --- /dev/null +++ b/lib/libc/gen/frexp.3 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd March 4, 2005 +.Dt FREXP 3 +.Os +.Sh NAME +.Nm frexp , +.Nm frexpf , +.Nm frexpl +.Nd convert floating-point number to fractional and integral components +.Sh LIBRARY +.Lb libm +.Sh SYNOPSIS +.In math.h +.Ft double +.Fn frexp "double value" "int *exp" +.Ft float +.Fn frexpf "float value" "int *exp" +.Ft long double +.Fn frexpl "long double value" "int *exp" +.Sh DESCRIPTION +The +.Fn frexp , +.Fn frexpf +and +.Fn frexpl +functions break a floating-point number into a normalized +fraction and an integral power of 2. +They store the integer in the +.Vt int +object pointed to by +.Fa exp . +.Sh RETURN VALUES +These functions return the value +.Va x , +such that +.Va x +is a +.Vt double +with magnitude in the interval +.Eo [ 1/2 , 1 Ec ) +or zero, and +.Fa value +equals +.Va x +times 2 raised to the power +.Fa *exp . +If +.Fa value +is zero, both parts of the result are zero. +.Sh SEE ALSO +.Xr ldexp 3 , +.Xr math 3 , +.Xr modf 3 +.Sh STANDARDS +The +.Fn frexp , +.Fn frexpf , +and +.Fn frexpl +functions conform to +.St -isoC-99 . diff --git a/lib/libc/gen/frexp.c b/lib/libc/gen/frexp.c new file mode 100644 index 000000000000..4207d5d7e9b7 --- /dev/null +++ b/lib/libc/gen/frexp.c @@ -0,0 +1,57 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <math.h> + +#include "fpmath.h" + +double +frexp(double d, int *ex) +{ + union IEEEd2bits u; + + u.d = d; + switch (u.bits.exp) { + case 0: /* 0 or subnormal */ + if ((u.bits.manl | u.bits.manh) == 0) { + *ex = 0; + } else { + u.d *= 0x1.0p514; + *ex = u.bits.exp - 1536; + u.bits.exp = 1022; + } + break; + case 2047: /* infinity or NaN; value of *ex is unspecified */ + break; + default: /* normal */ + *ex = u.bits.exp - 1022; + u.bits.exp = 1022; + break; + } + return (u.d); +} diff --git a/lib/libc/gen/fstab.c b/lib/libc/gen/fstab.c new file mode 100644 index 000000000000..ae21b4696883 --- /dev/null +++ b/lib/libc/gen/fstab.c @@ -0,0 +1,294 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1980, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fstab.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <vis.h> +#include "un-namespace.h" + +static FILE *_fs_fp; +static struct fstab _fs_fstab; +static int LineNo = 0; +static char *path_fstab; +static char fstab_path[PATH_MAX]; +static int fsp_set = 0; + +static void error(int); +static void fixfsfile(void); +static int fstabscan(void); + +void +setfstab(const char *file) +{ + + if (file == NULL) { + path_fstab = _PATH_FSTAB; + } else { + strncpy(fstab_path, file, PATH_MAX); + fstab_path[PATH_MAX - 1] = '\0'; + path_fstab = fstab_path; + } + fsp_set = 1; + + return; +} + +const char * +getfstab(void) +{ + + if (fsp_set) + return (path_fstab); + else + return (_PATH_FSTAB); +} + +static void +fixfsfile(void) +{ + static char buf[sizeof(_PATH_DEV) + MNAMELEN]; + struct stat sb; + struct statfs sf; + + if (_fs_fstab.fs_file != NULL && strcmp(_fs_fstab.fs_file, "/") != 0) + return; + if (statfs("/", &sf) != 0) + return; + if (sf.f_mntfromname[0] == '/') + buf[0] = '\0'; + else + strcpy(buf, _PATH_DEV); + strcat(buf, sf.f_mntfromname); + if (stat(buf, &sb) != 0 || + (!S_ISBLK(sb.st_mode) && !S_ISCHR(sb.st_mode))) + return; + _fs_fstab.fs_spec = buf; +} + +static int +fstabscan(void) +{ + char *cp, *p; +#define MAXLINELENGTH 1024 + static char line[MAXLINELENGTH]; + char subline[MAXLINELENGTH]; + int typexx; + + for (;;) { + + if (!(p = fgets(line, sizeof(line), _fs_fp))) + return (0); +/* OLD_STYLE_FSTAB */ + ++LineNo; + if (*line == '#' || *line == '\n') + continue; + if (!strpbrk(p, " \t")) { + _fs_fstab.fs_spec = strsep(&p, ":\n"); + _fs_fstab.fs_file = strsep(&p, ":\n"); + fixfsfile(); + _fs_fstab.fs_type = strsep(&p, ":\n"); + if (_fs_fstab.fs_type) { + if (!strcmp(_fs_fstab.fs_type, FSTAB_XX)) + continue; + _fs_fstab.fs_mntops = _fs_fstab.fs_type; + _fs_fstab.fs_vfstype = + strcmp(_fs_fstab.fs_type, FSTAB_SW) ? + "ufs" : "swap"; + if ((cp = strsep(&p, ":\n")) != NULL) { + _fs_fstab.fs_freq = atoi(cp); + if ((cp = strsep(&p, ":\n")) != NULL) { + _fs_fstab.fs_passno = atoi(cp); + return (1); + } + } + } + goto bad; + } +/* OLD_STYLE_FSTAB */ + while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0') + ; + _fs_fstab.fs_spec = cp; + if (_fs_fstab.fs_spec == NULL || *_fs_fstab.fs_spec == '#') + continue; + if (strunvis(_fs_fstab.fs_spec, _fs_fstab.fs_spec) < 0) + goto bad; + while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0') + ; + _fs_fstab.fs_file = cp; + if (_fs_fstab.fs_file == NULL) + goto bad; + if (strunvis(_fs_fstab.fs_file, _fs_fstab.fs_file) < 0) + goto bad; + fixfsfile(); + while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0') + ; + _fs_fstab.fs_vfstype = cp; + while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0') + ; + _fs_fstab.fs_mntops = cp; + if (_fs_fstab.fs_mntops == NULL) + goto bad; + _fs_fstab.fs_freq = 0; + _fs_fstab.fs_passno = 0; + while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0') + ; + if (cp != NULL) { + _fs_fstab.fs_freq = atoi(cp); + while ((cp = strsep(&p, " \t\n")) != NULL && *cp == '\0') + ; + if (cp != NULL) + _fs_fstab.fs_passno = atoi(cp); + } + (void)strlcpy(subline, _fs_fstab.fs_mntops, sizeof(subline)); + p = subline; + for (typexx = 0, cp = strsep(&p, ","); cp; + cp = strsep(&p, ",")) { + if (strlen(cp) != 2) + continue; + if (!strcmp(cp, FSTAB_RW)) { + _fs_fstab.fs_type = FSTAB_RW; + break; + } + if (!strcmp(cp, FSTAB_RQ)) { + _fs_fstab.fs_type = FSTAB_RQ; + break; + } + if (!strcmp(cp, FSTAB_RO)) { + _fs_fstab.fs_type = FSTAB_RO; + break; + } + if (!strcmp(cp, FSTAB_SW)) { + _fs_fstab.fs_type = FSTAB_SW; + break; + } + if (!strcmp(cp, FSTAB_XX)) { + _fs_fstab.fs_type = FSTAB_XX; + typexx++; + break; + } + } + if (typexx) + continue; + if (cp != NULL) + return (1); + +bad: /* no way to distinguish between EOF and syntax error */ + error(EFTYPE); + } + /* NOTREACHED */ +} + +struct fstab * +getfsent(void) +{ + + if ((!_fs_fp && !setfsent()) || !fstabscan()) + return (NULL); + return (&_fs_fstab); +} + +struct fstab * +getfsspec(const char *name) +{ + + if (setfsent()) + while (fstabscan()) + if (!strcmp(_fs_fstab.fs_spec, name)) + return (&_fs_fstab); + return (NULL); +} + +struct fstab * +getfsfile(const char *name) +{ + + if (setfsent()) + while (fstabscan()) + if (!strcmp(_fs_fstab.fs_file, name)) + return (&_fs_fstab); + return (NULL); +} + +int +setfsent(void) +{ + if (_fs_fp) { + rewind(_fs_fp); + LineNo = 0; + return (1); + } + if (fsp_set == 0) + setfstab(secure_getenv("PATH_FSTAB")); + if ((_fs_fp = fopen(path_fstab, "re")) != NULL) { + LineNo = 0; + return (1); + } + error(errno); + return (0); +} + +void +endfsent(void) +{ + + if (_fs_fp) { + (void)fclose(_fs_fp); + _fs_fp = NULL; + } + + fsp_set = 0; +} + +static void +error(int err) +{ + char *p; + char num[30]; + + (void)_write(STDERR_FILENO, "fstab: ", 7); + (void)_write(STDERR_FILENO, path_fstab, strlen(path_fstab)); + (void)_write(STDERR_FILENO, ":", 1); + sprintf(num, "%d: ", LineNo); + (void)_write(STDERR_FILENO, num, strlen(num)); + p = strerror(err); + (void)_write(STDERR_FILENO, p, strlen(p)); + (void)_write(STDERR_FILENO, "\n", 1); +} diff --git a/lib/libc/gen/ftok.3 b/lib/libc/gen/ftok.3 new file mode 100644 index 000000000000..490d93cc1f67 --- /dev/null +++ b/lib/libc/gen/ftok.3 @@ -0,0 +1,80 @@ +.\" Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +.\" PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +.\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +.\" OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +.\" ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.Dd November 28, 2022 +.Dt FTOK 3 +.Os +.Sh NAME +.Nm ftok +.Nd create IPC identifier from path name +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/ipc.h +.Ft key_t +.Fn ftok "const char *path" "int id" +.Sh DESCRIPTION +The +.Fn ftok +function attempts to create a unique key suitable for use with the +.Xr msgget 2 , +.Xr semget 2 +and +.Xr shmget 2 +functions given the +.Fa path +of an existing file and a user-selectable +.Fa id . +.Pp +The specified +.Fa path +must specify an existing file that is accessible to the calling process +or the call will fail. +Also, note that links to files will return the +same key, given the same +.Fa id . +.Sh RETURN VALUES +The +.Fn ftok +function will return -1 if +.Fa path +does not exist or if it cannot be accessed by the calling process. +.Sh SEE ALSO +.Xr msgget 2 , +.Xr semget 2 , +.Xr shmget 2 +.Sh HISTORY +The +.Fn ftok +function originates with System V and is typically used by programs +that use the System V IPC routines. +.Sh AUTHORS +.An Thorsten Lockert Aq Mt tholo@sigmasoft.com +.Sh BUGS +The returned key is computed based on the device minor number and inode of the +specified +.Fa path +in combination with the lower 8 bits of the given +.Fa id . +Thus it is quite possible for the routine to return duplicate keys. diff --git a/lib/libc/gen/ftok.c b/lib/libc/gen/ftok.c new file mode 100644 index 000000000000..04fa5d464fb0 --- /dev/null +++ b/lib/libc/gen/ftok.c @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1994 SigmaSoft, Th. Lockert <tholo@sigmasoft.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ipc.h> + +key_t +ftok(const char *path, int id) +{ + struct stat st; + + if (stat(path, &st) < 0) + return (key_t)-1; + + return ((key_t)((unsigned int)id << 24 | (st.st_dev & 0xff) << 16 | + (st.st_ino & 0xffff))); +} diff --git a/lib/libc/gen/fts-compat.c b/lib/libc/gen/fts-compat.c new file mode 100644 index 000000000000..62a1e0a81f62 --- /dev/null +++ b/lib/libc/gen/fts-compat.c @@ -0,0 +1,1235 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * From: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ + */ + +#include "namespace.h" +#include <sys/param.h> +#define _WANT_FREEBSD11_STATFS +#include <sys/mount.h> +#define _WANT_FREEBSD11_STAT +#include <sys/stat.h> + +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "fts-compat.h" +#include "un-namespace.h" +#include "gen-compat.h" + +#include "gen-private.h" + +FTSENT *__fts_children_44bsd(FTS *, int); +int __fts_close_44bsd(FTS *); +void *__fts_get_clientptr_44bsd(FTS *); +FTS *__fts_get_stream_44bsd(FTSENT *); +FTS *__fts_open_44bsd(char * const *, int, + int (*)(const FTSENT * const *, const FTSENT * const *)); +FTSENT *__fts_read_44bsd(FTS *); +int __fts_set_44bsd(FTS *, FTSENT *, int); +void __fts_set_clientptr_44bsd(FTS *, void *); + +static FTSENT *fts_alloc(FTS *, char *, int); +static FTSENT *fts_build(FTS *, int); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static void fts_padjust(FTS *, FTSENT *); +static int fts_palloc(FTS *, size_t); +static FTSENT *fts_sort(FTS *, FTSENT *, int); +static u_short fts_stat(FTS *, FTSENT *, int); +static int fts_safe_changedir(FTS *, FTSENT *, int, char *); +static int fts_ufslinks(FTS *, const FTSENT *); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +/* + * Internal representation of an FTS, including extra implementation + * details. The FTS returned from fts_open points to this structure's + * ftsp_fts member (and can be cast to an _fts_private as required) + */ +struct _fts_private { + FTS ftsp_fts; + struct freebsd11_statfs ftsp_statfs; + uint32_t ftsp_dev; + int ftsp_linksreliable; +}; + +/* + * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it + * knows that a directory could not possibly have subdirectories. This + * is decided by looking at the link count: a subdirectory would + * increment its parent's link count by virtue of its own ".." entry. + * This assumption only holds for UFS-like filesystems that implement + * links and directories this way, so we must punt for others. + */ + +static const char *ufslike_filesystems[] = { + "ufs", + "zfs", + "nfs", + "ext2fs", + 0 +}; + +FTS * +__fts_open_44bsd(char * const *argv, int options, + int (*compar)(const FTSENT * const *, const FTSENT * const *)) +{ + struct _fts_private *priv; + FTS *sp; + FTSENT *p, *root; + int nitems; + FTSENT *parent, *tmp; + int len; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; + sp->fts_compar = compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Shush, GCC. */ + tmp = NULL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { + /* Don't allow zero-length paths. */ + if ((len = strlen(*argv)) == 0) { + errno = ENOENT; + goto mem3; + } + + p = fts_alloc(sp, *argv, len); + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW)); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ + if (!ISSET(FTS_NOCHDIR) && + (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + SET(FTS_NOCHDIR); + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS *sp, FTSENT *p) +{ + int len; + char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +__fts_close_44bsd(FTS *sp) +{ + FTSENT *freep, *p; + int saved_errno; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link != NULL ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + saved_errno = fchdir(sp->fts_rfd) ? errno : 0; + (void)_close(sp->fts_rfd); + + /* Set errno and return. */ + if (saved_errno != 0) { + /* Free up the stream pointer. */ + free(sp); + errno = saved_errno; + return (-1); + } + } + + /* Free up the stream pointer. */ + free(sp); + return (0); +} + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +FTSENT * +__fts_read_44bsd(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + char *t; + int saved_errno; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC, + 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)_close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child != NULL) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p != NULL; + p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link) != NULL) { + free(tmp); + + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) + goto next; + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + free(tmp); + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)_close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)_close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +__fts_set_44bsd(FTS *sp, FTSENT *p, int instr) +{ + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +__fts_children_44bsd(FTS *sp, int instr) +{ + FTSENT *p; + int fd; + + if (instr != 0 && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child != NULL) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); + if (fchdir(fd)) { + (void)_close(fd); + return (NULL); + } + (void)_close(fd); + return (sp->fts_child); +} + +#ifndef fts_get_clientptr +#error "fts_get_clientptr not defined" +#endif + +void * +(__fts_get_clientptr_44bsd)(FTS *sp) +{ + + return (fts_get_clientptr(sp)); +} + +#ifndef fts_get_stream +#error "fts_get_stream not defined" +#endif + +FTS * +(__fts_get_stream_44bsd)(FTSENT *p) +{ + return (fts_get_stream(p)); +} + +void +__fts_set_clientptr_44bsd(FTS *sp, void *clientptr) +{ + + sp->fts_clientptr = clientptr; +} + +static struct freebsd11_dirent * +fts_safe_readdir(DIR *dirp, int *readdir_errno) +{ + struct freebsd11_dirent *ret; + + errno = 0; + if (!dirp) + return (NULL); + ret = freebsd11_readdir(dirp); + *readdir_errno = errno; + return (ret); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(FTS *sp, int type) +{ + struct freebsd11_dirent *dp; + FTSENT *p, *head; + int nitems; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + int cderrno, descend, len, level, maxlen, nlinks, oflag, saved_errno, + nostat, doadjust, dnamlen, readdir_errno; + char *cp; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ +#ifdef FTS_WHITEOUT + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP; + else + oflag = DTF_HIDEW | DTF_NODUP; +#else +#define __opendir2(path, flag) opendir(path) +#endif + if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + /* Be quiet about nostat, GCC. */ + nostat = 0; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + if (fts_ufslinks(sp, cur)) + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + else + nlinks = -1; + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } else { + /* GCC, you're too verbose. */ + cp = NULL; + } + len++; + maxlen = sp->fts_pathlen - len; + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + readdir_errno = 0; + for (head = tail = NULL, nitems = 0; + (dp = fts_safe_readdir(dirp, &readdir_errno));) { + dnamlen = dp->d_namlen; + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) + goto mem1; + if (dnamlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dnamlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = saved_errno; + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + + if (len + dnamlen >= USHRT_MAX) { + /* + * In an FTSENT, fts_pathlen is a u_short so it is + * possible to wraparound here. If we do, free up + * the current structure and the structures already + * allocated, then error out with ENAMETOOLONG. + */ + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = ENAMETOOLONG; + return (NULL); + } + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + dnamlen; + +#ifdef FTS_WHITEOUT + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; +#endif + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, p->fts_namelen + 1); + } else + p->fts_accpath = p->fts_name; + /* Stat it. */ + p->fts_info = fts_stat(sp, p, 0); + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + + if (readdir_errno) { + cur->fts_errno = readdir_errno; + /* + * If we've not read any items yet, treat + * the error as if we can't access the dir. + */ + cur->fts_info = nitems ? FTS_ERR : FTS_DNR; + } + + if (dirp) + (void)closedir(dirp); + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) { + if (len == sp->fts_pathlen || nitems == 0) + --cp; + *cp = '\0'; + } + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD && + cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static u_short +fts_stat(FTS *sp, FTSENT *p, int follow) +{ + FTSENT *t; + uint32_t dev; + uint32_t ino; + struct freebsd11_stat *sbp, sb; + int saved_errno; + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + +#ifdef FTS_WHITEOUT + /* Check for whiteout. */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof(*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } +#endif + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (freebsd11_stat(p->fts_accpath, sbp)) { + saved_errno = errno; + if (!freebsd11_lstat(p->fts_accpath, sbp)) { + errno = 0; + return (FTS_SLNONE); + } + p->fts_errno = saved_errno; + goto err; + } + } else if (freebsd11_lstat(p->fts_accpath, sbp)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(*sbp)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +/* + * The comparison function takes pointers to pointers to FTSENT structures. + * Qsort wants a comparison function that takes pointers to void. + * (Both with appropriate levels of const-poisoning, of course!) + * Use a trampoline function to deal with the difference. + */ +static int +fts_compar(const void *a, const void *b) +{ + FTS *parent; + + parent = (*(const FTSENT * const *)a)->fts_fts; + return (*parent->fts_compar)(a, b); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, int nitems) +{ + FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + sp->fts_nitems = nitems + 40; + if ((sp->fts_array = reallocf(sp->fts_array, + sp->fts_nitems * sizeof(FTSENT *))) == NULL) { + sp->fts_nitems = 0; + return (head); + } + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort(sp->fts_array, nitems, sizeof(FTSENT *), fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, char *name, int namelen) +{ + FTSENT *p; + size_t len; + + struct ftsent_withstat { + FTSENT ent; + struct freebsd11_stat statbuf; + }; + + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. + */ + if (ISSET(FTS_NOSTAT)) + len = sizeof(FTSENT) + namelen + 1; + else + len = sizeof(struct ftsent_withstat) + namelen + 1; + + if ((p = malloc(len)) == NULL) + return (NULL); + + if (ISSET(FTS_NOSTAT)) { + p->fts_name = (char *)(p + 1); + p->fts_statp = NULL; + } else { + p->fts_name = (char *)((struct ftsent_withstat *)p + 1); + p->fts_statp = &((struct ftsent_withstat *)p)->statbuf; + } + + /* Copy the name and guarantee NUL termination. */ + memcpy(p->fts_name, name, namelen); + p->fts_name[namelen] = '\0'; + p->fts_namelen = namelen; + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + p->fts_fts = sp; + return (p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t more) +{ + + sp->fts_pathlen += more + 256; + /* + * Check for possible wraparound. In an FTS, fts_pathlen is + * a signed int but in an FTSENT it is an unsigned short. + * We limit fts_pathlen to USHRT_MAX to be safe in both cases. + */ + if (sp->fts_pathlen < 0 || sp->fts_pathlen >= USHRT_MAX) { + if (sp->fts_path) + free(sp->fts_path); + sp->fts_path = NULL; + errno = ENAMETOOLONG; + return (1); + } + sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); + return (sp->fts_path == NULL); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr = sp->fts_path; + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} while (0) + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) +{ + int ret, oerrno, newfd; + struct freebsd11_stat sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = _open(path, O_RDONLY | O_CLOEXEC, 0)) < 0) + return (-1); + if (freebsd11_fstat(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + errno = ENOENT; /* disinformation */ + ret = -1; + goto bail; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)_close(newfd); + errno = oerrno; + return (ret); +} + +/* + * Check if the filesystem for "ent" has UFS-style links. + */ +static int +fts_ufslinks(FTS *sp, const FTSENT *ent) +{ + struct _fts_private *priv; + const char **cpp; + + priv = (struct _fts_private *)sp; + /* + * If this node's device is different from the previous, grab + * the filesystem information, and decide on the reliability + * of the link information from this filesystem for stat(2) + * avoidance. + */ + if (priv->ftsp_dev != ent->fts_dev) { + if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { + priv->ftsp_dev = ent->fts_dev; + priv->ftsp_linksreliable = 0; + for (cpp = ufslike_filesystems; *cpp; cpp++) { + if (strcmp(priv->ftsp_statfs.f_fstypename, + *cpp) == 0) { + priv->ftsp_linksreliable = 1; + break; + } + } + } else { + priv->ftsp_linksreliable = 0; + } + } + return (priv->ftsp_linksreliable); +} + +__sym_compat(fts_open, __fts_open_44bsd, FBSD_1.0); +__sym_compat(fts_close, __fts_close_44bsd, FBSD_1.0); +__sym_compat(fts_read, __fts_read_44bsd, FBSD_1.0); +__sym_compat(fts_set, __fts_set_44bsd, FBSD_1.0); +__sym_compat(fts_children, __fts_children_44bsd, FBSD_1.0); +__sym_compat(fts_get_clientptr, __fts_get_clientptr_44bsd, FBSD_1.0); +__sym_compat(fts_get_stream, __fts_get_stream_44bsd, FBSD_1.0); +__sym_compat(fts_set_clientptr, __fts_set_clientptr_44bsd, FBSD_1.0); diff --git a/lib/libc/gen/fts-compat.h b/lib/libc/gen/fts-compat.h new file mode 100644 index 000000000000..d522e3befedb --- /dev/null +++ b/lib/libc/gen/fts-compat.h @@ -0,0 +1,127 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FTS_H_ +#define _FTS_H_ + +typedef struct { + struct _ftsent *fts_cur; /* current node */ + struct _ftsent *fts_child; /* linked list of children */ + struct _ftsent **fts_array; /* sort array */ + uint32_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + int fts_rfd; /* fd for root */ + int fts_pathlen; /* sizeof(path) */ + int fts_nitems; /* elements in the sort array */ + int (*fts_compar) /* compare function */ + (const struct _ftsent * const *, const struct _ftsent * const *); + +#define FTS_COMFOLLOW 0x001 /* follow command line symlinks */ +#define FTS_LOGICAL 0x002 /* logical walk */ +#define FTS_NOCHDIR 0x004 /* don't change directories */ +#define FTS_NOSTAT 0x008 /* don't get stat info */ +#define FTS_PHYSICAL 0x010 /* physical walk */ +#define FTS_SEEDOT 0x020 /* return dot and dot-dot */ +#define FTS_XDEV 0x040 /* don't cross devices */ +#define FTS_WHITEOUT 0x080 /* return whiteout information */ +#define FTS_OPTIONMASK 0x0ff /* valid user option mask */ + +#define FTS_NAMEONLY 0x100 /* (private) child names only */ +#define FTS_STOP 0x200 /* (private) unrecoverable error */ + int fts_options; /* fts_open options, global flags */ + void *fts_clientptr; /* thunk for sort function */ +} FTS; + +typedef struct _ftsent { + struct _ftsent *fts_cycle; /* cycle node */ + struct _ftsent *fts_parent; /* parent directory */ + struct _ftsent *fts_link; /* next file in directory */ + union { + struct { + long __fts_number; /* local numeric value */ + void *__fts_pointer; /* local address value */ + } __struct_ftsent; + int64_t __fts_bignum; + } __union_ftsent; +#define fts_number __union_ftsent.__struct_ftsent.__fts_number +#define fts_pointer __union_ftsent.__struct_ftsent.__fts_pointer +#define fts_bignum __union_ftsent.__fts_bignum + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + int fts_symfd; /* fd for symlink */ + u_short fts_pathlen; /* strlen(fts_path) */ + u_short fts_namelen; /* strlen(fts_name) */ + + uint32_t fts_ino; /* inode */ + uint32_t fts_dev; /* device */ + uint16_t fts_nlink; /* link count */ + +#define FTS_ROOTPARENTLEVEL -1 +#define FTS_ROOTLEVEL 0 + short fts_level; /* depth (-1 to N) */ + +#define FTS_D 1 /* preorder directory */ +#define FTS_DC 2 /* directory that causes cycles */ +#define FTS_DEFAULT 3 /* none of the above */ +#define FTS_DNR 4 /* unreadable directory */ +#define FTS_DOT 5 /* dot or dot-dot */ +#define FTS_DP 6 /* postorder directory */ +#define FTS_ERR 7 /* error; errno is set */ +#define FTS_F 8 /* regular file */ +#define FTS_INIT 9 /* initialized only */ +#define FTS_NS 10 /* stat(2) failed */ +#define FTS_NSOK 11 /* no stat(2) requested */ +#define FTS_SL 12 /* symbolic link */ +#define FTS_SLNONE 13 /* symbolic link without target */ +#define FTS_W 14 /* whiteout object */ + u_short fts_info; /* user flags for FTSENT structure */ + +#define FTS_DONTCHDIR 0x01 /* don't chdir .. to the parent */ +#define FTS_SYMFOLLOW 0x02 /* followed a symlink to get here */ +#define FTS_ISW 0x04 /* this is a whiteout object */ + u_short fts_flags; /* private flags for FTSENT structure */ + +#define FTS_AGAIN 1 /* read node again */ +#define FTS_FOLLOW 2 /* follow symbolic link */ +#define FTS_NOINSTR 3 /* no instructions */ +#define FTS_SKIP 4 /* discard node */ + u_short fts_instr; /* fts_set() instructions */ + + struct freebsd11_stat *fts_statp; /* stat(2) information */ + char *fts_name; /* file name */ + FTS *fts_fts; /* back pointer to main FTS */ +} FTSENT; + +#define fts_get_clientptr(fts) ((fts)->fts_clientptr) +#define fts_get_stream(ftsent) ((ftsent)->fts_fts) + +#endif /* !_FTS_H_ */ diff --git a/lib/libc/gen/fts-compat11.c b/lib/libc/gen/fts-compat11.c new file mode 100644 index 000000000000..5abb378f5f08 --- /dev/null +++ b/lib/libc/gen/fts-compat11.c @@ -0,0 +1,1215 @@ +/*- + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * From: $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ + */ + +#include "namespace.h" +#include <sys/param.h> +#define _WANT_FREEBSD11_STATFS +#include <sys/mount.h> +#define _WANT_FREEBSD11_STAT +#include <sys/stat.h> + +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "fts-compat11.h" +#include "un-namespace.h" +#include "gen-compat.h" + +#include "gen-private.h" + +static FTSENT11 *fts_alloc(FTS11 *, char *, size_t); +static FTSENT11 *fts_build(FTS11 *, int); +static void fts_lfree(FTSENT11 *); +static void fts_load(FTS11 *, FTSENT11 *); +static size_t fts_maxarglen(char * const *); +static void fts_padjust(FTS11 *, FTSENT11 *); +static int fts_palloc(FTS11 *, size_t); +static FTSENT11 *fts_sort(FTS11 *, FTSENT11 *, size_t); +static int fts_stat(FTS11 *, FTSENT11 *, int, int); +static int fts_safe_changedir(FTS11 *, FTSENT11 *, int, char *); +static int fts_ufslinks(FTS11 *, const FTSENT11 *); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +/* + * Internal representation of an FTS, including extra implementation + * details. The FTS returned from fts_open points to this structure's + * ftsp_fts member (and can be cast to an _fts_private as required) + */ +struct _fts_private11 { + FTS11 ftsp_fts; + struct freebsd11_statfs ftsp_statfs; + uint32_t ftsp_dev; + int ftsp_linksreliable; +}; + +/* + * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it + * knows that a directory could not possibly have subdirectories. This + * is decided by looking at the link count: a subdirectory would + * increment its parent's link count by virtue of its own ".." entry. + * This assumption only holds for UFS-like filesystems that implement + * links and directories this way, so we must punt for others. + */ + +static const char *ufslike_filesystems[] = { + "ufs", + "zfs", + "nfs", + "ext2fs", + 0 +}; + +FTS11 * +freebsd11_fts_open(char * const *argv, int options, + int (*compar)(const FTSENT11 * const *, const FTSENT11 * const *)) +{ + struct _fts_private11 *priv; + FTS11 *sp; + FTSENT11 *p, *root; + FTSENT11 *parent, *tmp; + size_t len, nitems; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; + sp->fts_compar = compar; + sp->fts_options = options; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Shush, GCC. */ + tmp = NULL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { + len = strlen(*argv); + + p = fts_alloc(sp, *argv, len); + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, ISSET(FTS_COMFOLLOW), -1); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ + if (!ISSET(FTS_NOCHDIR) && + (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + SET(FTS_NOCHDIR); + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +static void +fts_load(FTS11 *sp, FTSENT11 *p) +{ + size_t len; + char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +freebsd11_fts_close(FTS11 *sp) +{ + FTSENT11 *freep, *p; + int saved_errno; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link != NULL ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + saved_errno = fchdir(sp->fts_rfd) ? errno : 0; + (void)_close(sp->fts_rfd); + + /* Set errno and return. */ + if (saved_errno != 0) { + /* Free up the stream pointer. */ + free(sp); + errno = saved_errno; + return (-1); + } + } + + /* Free up the stream pointer. */ + free(sp); + return (0); +} + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +FTSENT11 * +freebsd11_fts_read(FTS11 *sp) +{ + FTSENT11 *p, *tmp; + int instr; + char *t; + int saved_errno; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0, -1); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC, + 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)_close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child != NULL) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p != NULL; + p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link) != NULL) { + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + free(tmp); + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) { + free(tmp); + goto next; + } + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + + free(tmp); + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(tmp); + free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)_close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)_close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + free(tmp); + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +freebsd11_fts_set(FTS11 *sp, FTSENT11 *p, int instr) +{ + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT11 * +freebsd11_fts_children(FTS11 *sp, int instr) +{ + FTSENT11 *p; + int fd, rc, serrno; + + if (instr != 0 && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child != NULL) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); + serrno = (sp->fts_child == NULL) ? errno : 0; + rc = fchdir(fd); + if (rc < 0 && serrno == 0) + serrno = errno; + (void)_close(fd); + errno = serrno; + if (rc < 0) + return (NULL); + return (sp->fts_child); +} + +#ifndef freebsd11_fts_get_clientptr +#error "freebsd11_fts_get_clientptr not defined" +#endif + +void * +(freebsd11_fts_get_clientptr)(FTS11 *sp) +{ + + return (freebsd11_fts_get_clientptr(sp)); +} + +#ifndef freebsd11_fts_get_stream +#error "freebsd11_fts_get_stream not defined" +#endif + +FTS11 * +(freebsd11_fts_get_stream)(FTSENT11 *p) +{ + return (freebsd11_fts_get_stream(p)); +} + +void +freebsd11_fts_set_clientptr(FTS11 *sp, void *clientptr) +{ + + sp->fts_clientptr = clientptr; +} + +static struct freebsd11_dirent * +fts_safe_readdir(DIR *dirp, int *readdir_errno) +{ + struct freebsd11_dirent *ret; + + errno = 0; + if (!dirp) + return (NULL); + ret = freebsd11_readdir(dirp); + *readdir_errno = errno; + return (ret); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT11 * +fts_build(FTS11 *sp, int type) +{ + struct freebsd11_dirent *dp; + FTSENT11 *p, *head; + FTSENT11 *cur, *tail; + DIR *dirp; + void *oldaddr; + char *cp; + int cderrno, descend, oflag, saved_errno, nostat, doadjust, + readdir_errno; + long level; + long nlinks; /* has to be signed because -1 is a magic value */ + size_t dnamlen, len, maxlen, nitems; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ +#ifdef FTS_WHITEOUT + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP; + else + oflag = DTF_HIDEW | DTF_NODUP; +#else +#define __opendir2(path, flag) opendir(path) +#endif + if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + /* Be quiet about nostat, GCC. */ + nostat = 0; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + if (fts_ufslinks(sp, cur)) + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + else + nlinks = -1; + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } else { + /* GCC, you're too verbose. */ + cp = NULL; + } + len++; + maxlen = sp->fts_pathlen - len; + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + readdir_errno = 0; + for (head = tail = NULL, nitems = 0; + (dp = fts_safe_readdir(dirp, &readdir_errno));) { + dnamlen = dp->d_namlen; + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) + goto mem1; + if (dnamlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dnamlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = saved_errno; + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + dnamlen; + +#ifdef FTS_WHITEOUT + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; +#endif + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 +#ifdef DT_DIR + || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN) +#endif + ) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, p->fts_namelen + 1); + p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp)); + } else { + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, 0, -1); + } + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + + if (readdir_errno) { + cur->fts_errno = readdir_errno; + /* + * If we've not read any items yet, treat + * the error as if we can't access the dir. + */ + cur->fts_info = nitems ? FTS_ERR : FTS_DNR; + } + + if (dirp) + (void)closedir(dirp); + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) + sp->fts_path[cur->fts_pathlen] = '\0'; + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + fts_lfree(head); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD && + cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static int +fts_stat(FTS11 *sp, FTSENT11 *p, int follow, int dfd) +{ + FTSENT11 *t; + uint32_t dev; + uint32_t ino; + struct freebsd11_stat *sbp, sb; + int saved_errno; + const char *path; + + if (dfd == -1) + path = p->fts_accpath, dfd = AT_FDCWD; + else + path = p->fts_name; + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + +#ifdef FTS_WHITEOUT + /* Check for whiteout. */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof(*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } +#endif + + /* + * If doing a logical walk, or application requested FTS_FOLLOW, do + * a stat(2). If that fails, check for a non-existent symlink. If + * fail, set the errno from the stat call. + */ + if (ISSET(FTS_LOGICAL) || follow) { + if (freebsd11_fstatat(dfd, path, sbp, 0)) { + saved_errno = errno; + if (freebsd11_fstatat(dfd, path, sbp, + AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = saved_errno; + goto err; + } + errno = 0; + if (S_ISLNK(sbp->st_mode)) + return (FTS_SLNONE); + } + } else if (freebsd11_fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(*sbp)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +/* + * The comparison function takes pointers to pointers to FTSENT structures. + * Qsort wants a comparison function that takes pointers to void. + * (Both with appropriate levels of const-poisoning, of course!) + * Use a trampoline function to deal with the difference. + */ +static int +fts_compar(const void *a, const void *b) +{ + FTS11 *parent; + + parent = (*(const FTSENT11 * const *)a)->fts_fts; + return (*parent->fts_compar)(a, b); +} + +static FTSENT11 * +fts_sort(FTS11 *sp, FTSENT11 *head, size_t nitems) +{ + FTSENT11 **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + sp->fts_nitems = nitems + 40; + if ((sp->fts_array = reallocf(sp->fts_array, + sp->fts_nitems * sizeof(FTSENT11 *))) == NULL) { + sp->fts_nitems = 0; + return (head); + } + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + qsort(sp->fts_array, nitems, sizeof(FTSENT11 *), fts_compar); + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT11 * +fts_alloc(FTS11 *sp, char *name, size_t namelen) +{ + FTSENT11 *p; + size_t len; + + struct ftsent11_withstat { + FTSENT11 ent; + struct freebsd11_stat statbuf; + }; + + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. + */ + if (ISSET(FTS_NOSTAT)) + len = sizeof(FTSENT11) + namelen + 1; + else + len = sizeof(struct ftsent11_withstat) + namelen + 1; + + if ((p = malloc(len)) == NULL) + return (NULL); + + if (ISSET(FTS_NOSTAT)) { + p->fts_name = (char *)(p + 1); + p->fts_statp = NULL; + } else { + p->fts_name = (char *)((struct ftsent11_withstat *)p + 1); + p->fts_statp = &((struct ftsent11_withstat *)p)->statbuf; + } + + /* Copy the name and guarantee NUL termination. */ + memcpy(p->fts_name, name, namelen); + p->fts_name[namelen] = '\0'; + p->fts_namelen = namelen; + p->fts_path = sp->fts_path; + p->fts_errno = 0; + p->fts_flags = 0; + p->fts_instr = FTS_NOINSTR; + p->fts_number = 0; + p->fts_pointer = NULL; + p->fts_fts = sp; + return (p); +} + +static void +fts_lfree(FTSENT11 *head) +{ + FTSENT11 *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS11 *sp, size_t more) +{ + + sp->fts_pathlen += more + 256; + sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); + return (sp->fts_path == NULL); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS11 *sp, FTSENT11 *head) +{ + FTSENT11 *p; + char *addr = sp->fts_path; + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} while (0) + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(FTS11 *sp, FTSENT11 *p, int fd, char *path) +{ + int ret, oerrno, newfd; + struct freebsd11_stat sb; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY | + O_CLOEXEC, 0)) < 0) + return (-1); + if (freebsd11_fstat(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + errno = ENOENT; /* disinformation */ + ret = -1; + goto bail; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)_close(newfd); + errno = oerrno; + return (ret); +} + +/* + * Check if the filesystem for "ent" has UFS-style links. + */ +static int +fts_ufslinks(FTS11 *sp, const FTSENT11 *ent) +{ + struct _fts_private11 *priv; + const char **cpp; + + priv = (struct _fts_private11 *)sp; + /* + * If this node's device is different from the previous, grab + * the filesystem information, and decide on the reliability + * of the link information from this filesystem for stat(2) + * avoidance. + */ + if (priv->ftsp_dev != ent->fts_dev) { + if (freebsd11_statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { + priv->ftsp_dev = ent->fts_dev; + priv->ftsp_linksreliable = 0; + for (cpp = ufslike_filesystems; *cpp; cpp++) { + if (strcmp(priv->ftsp_statfs.f_fstypename, + *cpp) == 0) { + priv->ftsp_linksreliable = 1; + break; + } + } + } else { + priv->ftsp_linksreliable = 0; + } + } + return (priv->ftsp_linksreliable); +} + +__sym_compat(fts_open, freebsd11_fts_open, FBSD_1.1); +__sym_compat(fts_close, freebsd11_fts_close, FBSD_1.1); +__sym_compat(fts_read, freebsd11_fts_read, FBSD_1.1); +__sym_compat(fts_set, freebsd11_fts_set, FBSD_1.1); +__sym_compat(fts_children, freebsd11_fts_children, FBSD_1.1); +__sym_compat(fts_get_clientptr, freebsd11_fts_get_clientptr, FBSD_1.1); +__sym_compat(fts_get_stream, freebsd11_fts_get_stream, FBSD_1.1); +__sym_compat(fts_set_clientptr, freebsd11_fts_set_clientptr, FBSD_1.1); diff --git a/lib/libc/gen/fts-compat11.h b/lib/libc/gen/fts-compat11.h new file mode 100644 index 000000000000..f53e312374c5 --- /dev/null +++ b/lib/libc/gen/fts-compat11.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _FTS_COPMAT11_H_ +#define _FTS_COPMAT11_H_ + +typedef struct { + struct _ftsent11 *fts_cur; /* current node */ + struct _ftsent11 *fts_child; /* linked list of children */ + struct _ftsent11 **fts_array; /* sort array */ + uint32_t fts_dev; /* starting device # */ + char *fts_path; /* path for this descent */ + int fts_rfd; /* fd for root */ + __size_t fts_pathlen; /* sizeof(path) */ + __size_t fts_nitems; /* elements in the sort array */ + int (*fts_compar) /* compare function */ + (const struct _ftsent11 * const *, + const struct _ftsent11 * const *); + int fts_options; /* fts_open options, global flags */ + void *fts_clientptr; /* thunk for sort function */ +} FTS11; + +typedef struct _ftsent11 { + struct _ftsent11 *fts_cycle; /* cycle node */ + struct _ftsent11 *fts_parent; /* parent directory */ + struct _ftsent11 *fts_link; /* next file in directory */ + long long fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + int fts_errno; /* errno for this node */ + int fts_symfd; /* fd for symlink */ + __size_t fts_pathlen; /* strlen(fts_path) */ + __size_t fts_namelen; /* strlen(fts_name) */ + + uint32_t fts_ino; /* inode */ + uint32_t fts_dev; /* device */ + uint16_t fts_nlink; /* link count */ + + long fts_level; /* depth (-1 to N) */ + + int fts_info; /* user status for FTSENT structure */ + + unsigned fts_flags; /* private flags for FTSENT structure */ + + int fts_instr; /* fts_set() instructions */ + + struct freebsd11_stat *fts_statp; /* stat(2) information */ + char *fts_name; /* file name */ + FTS11 *fts_fts; /* back pointer to main FTS */ +} FTSENT11; + +FTSENT11 *freebsd11_fts_children(FTS11 *, int); +int freebsd11_fts_close(FTS11 *); +void *freebsd11_fts_get_clientptr(FTS11 *); +#define freebsd11_fts_get_clientptr(fts) ((fts)->fts_clientptr) +FTS11 *freebsd11_fts_get_stream(FTSENT11 *); +#define freebsd11_fts_get_stream(ftsent) ((ftsent)->fts_fts) +FTS11 *freebsd11_fts_open(char * const *, int, + int (*)(const FTSENT11 * const *, + const FTSENT11 * const *)); +FTSENT11 *freebsd11_fts_read(FTS11 *); +int freebsd11_fts_set(FTS11 *, FTSENT11 *, int); +void freebsd11_fts_set_clientptr(FTS11 *, void *); + +#endif /* !_FTS_COMPAT11_H_ */ diff --git a/lib/libc/gen/fts.3 b/lib/libc/gen/fts.3 new file mode 100644 index 000000000000..da304e59ee72 --- /dev/null +++ b/lib/libc/gen/fts.3 @@ -0,0 +1,1007 @@ +.\" Copyright (c) 1989, 1991, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 6, 2025 +.Dt FTS 3 +.Os +.Sh NAME +.Nm fts +.Nd traverse a file hierarchy +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In fts.h +.Ft FTS * +.Fn fts_open "char * const *path_argv" "int options" "int (*compar)(const FTSENT * const *, const FTSENT * const *)" +.Ft FTS * +.Fn fts_open_b "char * const *path_argv" "int options" "int (^compar)(const FTSENT * const *, const FTSENT * const *)" +.Ft FTSENT * +.Fn fts_read "FTS *ftsp" +.Ft FTSENT * +.Fn fts_children "FTS *ftsp" "int options" +.Ft int +.Fn fts_set "FTS *ftsp" "FTSENT *f" "int options" +.Ft void +.Fn fts_set_clientptr "FTS *ftsp" "void *clientdata" +.Ft void * +.Fn fts_get_clientptr "FTS *ftsp" +.Ft FTS * +.Fn fts_get_stream "FTSENT *f" +.Ft int +.Fn fts_close "FTS *ftsp" +.Sh DESCRIPTION +The +.Nm +functions are provided for traversing +.Ux +file hierarchies. +A simple overview is that the +.Fn fts_open +and +.Fn fts_open_b +functions return a +.Dq handle +on a file hierarchy, which is then supplied to +the other +.Nm +functions. +The +.Fn fts_read +function returns a pointer to a structure describing one of the files +in the file hierarchy. +The +.Fn fts_children +function returns a pointer to a linked list of structures, each of +which describes one of the files contained in a directory in the +hierarchy. +In general, directories are visited two distinguishable times; in pre-order +(before any of their descendants are visited) and in post-order (after all +of their descendants have been visited). +Files are visited once. +It is possible to walk the hierarchy +.Dq logically +(ignoring symbolic links) +or physically (visiting symbolic links), order the walk of the hierarchy or +prune and/or re-visit portions of the hierarchy. +.Pp +Two structures are defined (and typedef'd) in the include file +.In fts.h . +The first is +.Vt FTS , +the structure that represents the file hierarchy itself. +The second is +.Vt FTSENT , +the structure that represents a file in the file +hierarchy. +Normally, an +.Vt FTSENT +structure is returned for every file in the file +hierarchy. +In this manual page, +.Dq file +and +.Dq Vt FTSENT No structure +are generally +interchangeable. +.Pp +The +.Vt FTS +structure contains space for a single pointer, which may be used to +store application data or per-hierarchy state. +The +.Fn fts_set_clientptr +and +.Fn fts_get_clientptr +functions may be used to set and retrieve this pointer. +This is likely to be useful only when accessed from the sort +comparison function, which can determine the original +.Vt FTS +stream of its arguments using the +.Fn fts_get_stream +function. +The two +.Li get +functions are also available as macros of the same name. +.Pp +The +.Vt FTSENT +structure contains at least the following fields, which are +described in greater detail below: +.Bd -literal +typedef struct _ftsent { + int fts_info; /* status for FTSENT structure */ + char *fts_accpath; /* access path */ + char *fts_path; /* root path */ + size_t fts_pathlen; /* strlen(fts_path) */ + char *fts_name; /* file name */ + size_t fts_namelen; /* strlen(fts_name) */ + long fts_level; /* depth (\-1 to N) */ + int fts_errno; /* file errno */ + long long fts_number; /* local numeric value */ + void *fts_pointer; /* local address value */ + struct ftsent *fts_parent; /* parent directory */ + struct ftsent *fts_link; /* next file structure */ + struct ftsent *fts_cycle; /* cycle structure */ + struct stat *fts_statp; /* stat(2) information */ +} FTSENT; +.Ed +.Pp +These fields are defined as follows: +.Bl -tag -width "fts_namelen" +.It Fa fts_info +One of the following values describing the returned +.Vt FTSENT +structure and +the file it represents. +With the exception of directories without errors +.Pq Dv FTS_D , +all of these +entries are terminal, that is, they will not be revisited, nor will any +of their descendants be visited. +.Bl -tag -width FTS_DEFAULT +.It Dv FTS_D +A directory being visited in pre-order. +.It Dv FTS_DC +A directory that causes a cycle in the tree. +(The +.Fa fts_cycle +field of the +.Vt FTSENT +structure will be filled in as well.) +.It Dv FTS_DEFAULT +Any +.Vt FTSENT +structure that represents a file type not explicitly described +by one of the other +.Fa fts_info +values. +.It Dv FTS_DNR +A directory which cannot be read. +This immediately follows +.Dv FTS_D , +in place of +.Dv FTS_DP , +when the directory could not be entered, or could be entered but not +read. +This is an error return, and the +.Fa fts_errno +field will be set to indicate what caused the error. +.It Dv FTS_DOT +A file named +.Ql .\& +or +.Ql ..\& +which was not specified as a file name to +.Fn fts_open +or +.Fn fts_open_b +(see +.Dv FTS_SEEDOT ) . +.It Dv FTS_DP +A directory being visited in post-order. +The contents of the +.Vt FTSENT +structure will be unchanged from when +the directory was visited in pre-order, except for the +.Fa fts_info +field. +.It Dv FTS_ERR +This is an error return, and the +.Fa fts_errno +field will be set to indicate what caused the error. +.It Dv FTS_F +A regular file. +.It Dv FTS_NS +A file for which no +.Xr stat 2 +information was available. +The contents of the +.Fa fts_statp +field are undefined. +This is an error return, and the +.Fa fts_errno +field will be set to indicate what caused the error. +.It Dv FTS_NSOK +A file for which no +.Xr stat 2 +information was requested. +The contents of the +.Fa fts_statp +field are undefined. +.It Dv FTS_SL +A symbolic link. +.It Dv FTS_SLNONE +A symbolic link with a non-existent target. +The contents of the +.Fa fts_statp +field reference the file characteristic information for the symbolic link +itself. +.El +.It Fa fts_accpath +A path for accessing the file from the current directory. +.It Fa fts_path +The path for the file relative to the root of the traversal. +This path contains the path specified to +.Fn fts_open +or +.Fn fts_open_b +as a prefix. +.It Fa fts_pathlen +The length of the string referenced by +.Fa fts_path . +.It Fa fts_name +The name of the file. +.It Fa fts_namelen +The length of the string referenced by +.Fa fts_name . +.It Fa fts_level +The depth of the traversal, numbered from \-1 to N, where this file +was found. +The +.Vt FTSENT +structure representing the parent of the starting point (or root) +of the traversal is numbered +.Dv FTS_ROOTPARENTLEVEL +(\-1), and the +.Vt FTSENT +structure for the root +itself is numbered +.Dv FTS_ROOTLEVEL +(0). +.It Fa fts_errno +Upon return of a +.Vt FTSENT +structure from the +.Fn fts_children +or +.Fn fts_read +functions, with its +.Fa fts_info +field set to +.Dv FTS_DNR , +.Dv FTS_ERR +or +.Dv FTS_NS , +the +.Fa fts_errno +field contains the value of the external variable +.Va errno +specifying the cause of the error. +Otherwise, the contents of the +.Fa fts_errno +field are undefined. +.It Fa fts_number +This field is provided for the use of the application program and is +not modified by the +.Nm +functions. +It is initialized to 0. +.It Fa fts_pointer +This field is provided for the use of the application program and is +not modified by the +.Nm +functions. +It is initialized to +.Dv NULL . +.It Fa fts_parent +A pointer to the +.Vt FTSENT +structure referencing the file in the hierarchy +immediately above the current file, i.e., the directory of which this +file is a member. +A parent structure for the initial entry point is provided as well, +however, only the +.Fa fts_level , +.Fa fts_number +and +.Fa fts_pointer +fields are guaranteed to be initialized. +.It Fa fts_link +Upon return from the +.Fn fts_children +function, the +.Fa fts_link +field points to the next structure in the NULL-terminated linked list of +directory members. +Otherwise, the contents of the +.Fa fts_link +field are undefined. +.It Fa fts_cycle +If a directory causes a cycle in the hierarchy (see +.Dv FTS_DC ) , +either because +of a hard link between two directories, or a symbolic link pointing to a +directory, the +.Fa fts_cycle +field of the structure will point to the +.Vt FTSENT +structure in the hierarchy that references the same file as the current +.Vt FTSENT +structure. +Otherwise, the contents of the +.Fa fts_cycle +field are undefined. +.It Fa fts_statp +A pointer to +.Xr stat 2 +information for the file. +.El +.Pp +A single buffer is used for all of the paths of all of the files in the +file hierarchy. +Therefore, the +.Fa fts_path +and +.Fa fts_accpath +fields are guaranteed to be +.Dv NUL Ns -terminated +.Em only +for the file most recently returned by +.Fn fts_read . +To use these fields to reference any files represented by other +.Vt FTSENT +structures will require that the path buffer be modified using the +information contained in that +.Vt FTSENT +structure's +.Fa fts_pathlen +field. +Any such modifications should be undone before further calls to +.Fn fts_read +are attempted. +The +.Fa fts_name +field is always +.Dv NUL Ns -terminated . +.Ss Thread Safety +The +.Nm +functions can safely be used in multi-threaded programs provided no +two threads access the same +.Vt FTS +or +.Vt FTSENT +structure simultaneously. +However, unless the +.Dv FTS_NOCHDIR +flag was passed to +.Fn fts_open +or +.Fn fts_open_b , +calls to +.Fn fts_read +and +.Fn fts_children +may change the current working directory, which will affect all +threads. +Conversely, changing the current working directory either during or +between calls to +.Fn fts_read +or +.Fn fts_children +(even in a single-thread program) may cause +.Nm +to malfunction unless the +.Dv FTS_NOCHDIR +flag was passed to +.Fn fts_open +or +.Fn fts_open_b +and all paths in +.Va path_argv +were absolute. +.Ss Fn fts_open +The +.Fn fts_open +function takes a pointer to an array of character pointers naming one +or more paths which make up a logical file hierarchy to be traversed. +The array must be terminated by a +.Dv NULL +pointer. +.Pp +There are +a number of options, at least one of which (either +.Dv FTS_LOGICAL +or +.Dv FTS_PHYSICAL ) +must be specified. +The options are selected by +.Em or Ns 'ing +the following values: +.Bl -tag -width "FTS_COMFOLLOWDIR" +.It Dv FTS_COMFOLLOW +This option causes any symbolic link specified as a root path to be +followed immediately whether or not +.Dv FTS_LOGICAL +is also specified. +.It Dv FTS_COMFOLLOWDIR +This option is similar to +.Dv FTS_COMFOLLOW , +but only follows symbolic links to directories. +.It Dv FTS_LOGICAL +This option causes the +.Nm +routines to return +.Vt FTSENT +structures for the targets of symbolic links +instead of the symbolic links themselves. +If this option is set, the only symbolic links for which +.Vt FTSENT +structures +are returned to the application are those referencing non-existent files. +Either +.Dv FTS_LOGICAL +or +.Dv FTS_PHYSICAL +.Em must +be provided to the +.Fn fts_open +function. +.It Dv FTS_NOCHDIR +To allow descending to arbitrary depths +(independent of +.Brq Dv PATH_MAX ) +and improve performance, the +.Nm +functions change directories as they walk the file hierarchy. +This has the side-effect that an application cannot rely on being +in any particular directory during the traversal. +The +.Dv FTS_NOCHDIR +option turns off this feature, and the +.Nm +functions will not change the current directory. +Note that applications should not themselves change their current directory +and try to access files unless +.Dv FTS_NOCHDIR +is specified and absolute +pathnames were provided as arguments to +.Fn fts_open . +.It Dv FTS_NOSTAT +By default, returned +.Vt FTSENT +structures reference file characteristic information (the +.Fa statp +field) for each file visited. +This option relaxes that requirement as a performance optimization, +allowing the +.Nm +functions to set the +.Fa fts_info +field to +.Dv FTS_NSOK +and leave the contents of the +.Fa statp +field undefined. +.It Dv FTS_NOSTAT_TYPE +This option is similar to +.Dv FTS_NOSTAT , +but attempts to populate +.Fa fts_info +based on information from the +.Fa d_type +field of +.Vt struct dirent . +.It Dv FTS_PHYSICAL +This option causes the +.Nm +routines to return +.Vt FTSENT +structures for symbolic links themselves instead +of the target files they point to. +If this option is set, +.Vt FTSENT +structures for all symbolic links in the +hierarchy are returned to the application. +Either +.Dv FTS_LOGICAL +or +.Dv FTS_PHYSICAL +.Em must +be provided to the +.Fn fts_open +function. +.It Dv FTS_SEEDOT +By default, unless they are specified as path arguments to +.Fn fts_open , +any files named +.Ql .\& +or +.Ql ..\& +encountered in the file hierarchy are ignored. +This option causes the +.Nm +routines to return +.Vt FTSENT +structures for them. +.It Dv FTS_XDEV +This option prevents +.Nm +from descending into directories that have a different device number +than the file from which the descent began. +.El +.Pp +The +.Fa compar +argument points to a user-defined function which may be used to order +the traversal of the hierarchy. +It +takes two pointers to pointers to +.Vt FTSENT +structures as arguments and +should return a negative value, zero, or a positive value to indicate +if the file referenced by its first argument comes before, in any order +with respect to, or after, the file referenced by its second argument. +The +.Fa fts_accpath , +.Fa fts_path +and +.Fa fts_pathlen +fields of the +.Vt FTSENT +structures may +.Em never +be used in this comparison. +If the +.Fa fts_info +field is set to +.Dv FTS_NS +or +.Dv FTS_NSOK , +the +.Fa fts_statp +field may not either. +If the +.Fn compar +argument is +.Dv NULL , +the directory traversal order is in the order listed in +.Fa path_argv +for the root paths, and in the order listed in the directory for +everything else. +.Ss Fn fts_open_b +The +.Fn fts_open_b +function is identical to +.Fn fts_open +except that it takes a block pointer instead of a function pointer. +The block is copied before +.Fn fts_open_b +returns, so the original can safely go out of scope or be released. +.Ss Fn fts_read +The +.Fn fts_read +function returns a pointer to an +.Vt FTSENT +structure describing a file in +the hierarchy. +Directories (that are readable and do not cause cycles) are visited at +least twice, once in pre-order and once in post-order. +All other files are visited at least once. +(Hard links between directories that do not cause cycles or symbolic +links to symbolic links may cause files to be visited more than once, +or directories more than twice.) +.Pp +If all the members of the hierarchy have been returned, +.Fn fts_read +returns +.Dv NULL +and sets the external variable +.Va errno +to 0. +If an error unrelated to a file in the hierarchy occurs, +.Fn fts_read +returns +.Dv NULL +and sets +.Va errno +appropriately. +If an error related to a returned file occurs, a pointer to an +.Vt FTSENT +structure is returned, and +.Va errno +may or may not have been set (see +.Fa fts_info ) . +Note that +.Fn fts_read +will not set +.Va errno +to 0 if called again with the same +.Fa ftsp +argument after the +.Dv FTS_STOP +flag has been set or the end of the stream has been reached. +.Pp +The +.Vt FTSENT +structures returned by +.Fn fts_read +may be overwritten after a call to +.Fn fts_close +on the same file hierarchy stream, or, after a call to +.Fn fts_read +on the same file hierarchy stream unless they represent a file of type +directory, in which case they will not be overwritten until after a call to +.Fn fts_read +after the +.Vt FTSENT +structure has been returned by the +.Fn fts_read +function in post-order. +.Ss Fn fts_children +The +.Fn fts_children +function returns a pointer to an +.Vt FTSENT +structure describing the first entry in a NULL-terminated linked list of +the files in the directory represented by the +.Vt FTSENT +structure most recently returned by +.Fn fts_read . +The list is linked through the +.Fa fts_link +field of the +.Vt FTSENT +structure, and is ordered by the user-specified comparison function, if any. +Repeated calls to +.Fn fts_children +will recreate this linked list. +.Pp +As a special case, if +.Fn fts_read +has not yet been called for a hierarchy, +.Fn fts_children +will return a pointer to the files in the logical directory specified to +.Fn fts_open +or +.Fn fts_open_b , +i.e., the arguments specified to +.Fn fts_open +or +.Fn fts_open_b . +Otherwise, if the +.Vt FTSENT +structure most recently returned by +.Fn fts_read +is not a directory being visited in pre-order, +or the directory does not contain any files, +.Fn fts_children +returns +.Dv NULL +and sets +.Va errno +to zero. +If an error occurs, +.Fn fts_children +returns +.Dv NULL +and sets +.Va errno +appropriately. +.Pp +The +.Vt FTSENT +structures returned by +.Fn fts_children +may be overwritten after a call to +.Fn fts_children , +.Fn fts_close +or +.Fn fts_read +on the same file hierarchy stream. +.Pp +.Em Option +may be set to the following value: +.Bl -tag -width FTS_NAMEONLY +.It Dv FTS_NAMEONLY +Only the names of the files are needed. +The contents of all the fields in the returned linked list of structures +are undefined with the exception of the +.Fa fts_name +and +.Fa fts_namelen +fields. +.El +.Ss Fn fts_set +The +.Fn fts_set +function allows the user application to determine further processing +for the file +.Fa f +of the stream +.Fa ftsp . +The +.Fn fts_set +function +returns 0 on success, and \-1 if an error occurs. +.Em Option +must be set to one of the following values: +.Bl -tag -width FTS_PHYSICAL +.It Dv FTS_AGAIN +Re-visit the file; any file type may be re-visited. +The next call to +.Fn fts_read +will return the referenced file. +The +.Fa fts_stat +and +.Fa fts_info +fields of the structure will be reinitialized at that time, +but no other fields will have been changed. +This option is meaningful only for the most recently returned +file from +.Fn fts_read . +Normal use is for post-order directory visits, where it causes the +directory to be re-visited (in both pre and post-order) as well as all +of its descendants. +.It Dv FTS_FOLLOW +The referenced file must be a symbolic link. +If the referenced file is the one most recently returned by +.Fn fts_read , +the next call to +.Fn fts_read +returns the file with the +.Fa fts_info +and +.Fa fts_statp +fields reinitialized to reflect the target of the symbolic link instead +of the symbolic link itself. +If the file is one of those most recently returned by +.Fn fts_children , +the +.Fa fts_info +and +.Fa fts_statp +fields of the structure, when returned by +.Fn fts_read , +will reflect the target of the symbolic link instead of the symbolic link +itself. +In either case, if the target of the symbolic link does not exist the +fields of the returned structure will be unchanged and the +.Fa fts_info +field will be set to +.Dv FTS_SLNONE . +.Pp +If the target of the link is a directory, the pre-order return, followed +by the return of all of its descendants, followed by a post-order return, +is done. +.It Dv FTS_SKIP +No descendants of this file are visited. +The file may be one of those most recently returned by either +.Fn fts_children +or +.Fn fts_read . +.El +.Ss Fn fts_set_clientptr , Fn fts_get_clientptr +The +.Fn fts_set_clientptr +function sets the client data pointer for the stream +.Fa ftsp +to +.Fa clientdata . +The +.Fn fts_get_clientptr +function returns the client data pointer associated with +.Fa ftsp . +This can be used to pass per-stream data to the comparison function. +.Pp +For performance reasons, +.Fn fts_get_clientptr +may be shadowed by a preprocessor macro. +.Ss Fn fts_get_stream +The +.Fn fts_get_stream +function returns the +.Nm +stream associated with the file entry +.Fa f . +A typical use for this would be for a comparison function to first call +.Fn fts_get_stream +on one of its arguments, then call +.Fn fts_get_clientptr +to obtain the client data pointer, which in turn points to information +necessary to correctly order the two entries. +.Pp +For performance reasons, +.Fn fts_get_stream +may be shadowed by a preprocessor macro. +.Ss Fn fts_close +The +.Fn fts_close +function closes a file hierarchy stream +.Fa ftsp +and restores the current directory to the directory from which +.Fn fts_open +or +.Fn fts_open_b +was called to open +.Fa ftsp . +.Sh RETURN VALUES +The +.Fn fts_open +and +.Fn fts_open_b +functions return a pointer to the new +.Nm +stream on success and +.Dv NULL +on failure. +.Pp +The +.Fn fts_read +function returns a pointer to the next file entry on success, or if an +error occurs that relates specifically to that file entry. +On reaching the end of the file hierarchy, it returns +.Dv NULL +and sets the external variable +.Va errno +to 0. +On failure, it returns +.Dv NULL +and sets +.Va errno +to an appropriate non-zero value. +If called again after the +.Dv FTS_STOP +flag has been set or the end of the stream has been reached, +.Fn fts_read +returns +.Dv NULL +and leaves +.Va errno +untouched. +.Pp +The +.Fn fts_children +function returns a pointer to a linked list of file entries on +success. +On reaching the end of the file hierarchy, it returns +.Dv NULL +and sets the external variable +.Va errno +to 0. +On failure, it returns +.Dv NULL +and sets +.Va errno +to an appropriate non-zero value. +.Pp +The +.Fn fts_set +function returns 0 on success and \-1 if its +.Fa instr +argument is invalid. +.Pp +The +.Fn fts_get_clientptr +function returns the client data pointer associated with its argument, +or +.Dv NULL +if none has been set. +.Pp +The +.Fn fts_get_stream +function returns a pointer to the +.Nm +stream associated with its argument. +.Pp +The +.Fn fts_close +function +returns 0 on success, and \-1 if an error occurs. +.Sh ERRORS +The +.Fn fts_open +and +.Fn fts_open_b +functions may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr open 2 +and +.Xr malloc 3 . +The +.Fn fts_open_b +function may also fail and set +.Va errno +to +.Dv ENOSYS +if the blocks runtime is missing. +.Pp +The +.Fn fts_close +function may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr chdir 2 +and +.Xr close 2 . +.Pp +The +.Fn fts_read +and +.Fn fts_children +functions may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr chdir 2 , +.Xr malloc 3 , +.Xr opendir 3 , +.Xr readdir 3 +and +.Xr stat 2 . +.Pp +In addition, the +.Fn fts_children , +.Fn fts_open , +and +.Fn fts_set +functions may fail and set +.Va errno +as follows: +.Bl -tag -width Er +.It Bq Er EINVAL +The options were invalid, or the list was empty. +.El +.Sh SEE ALSO +.Xr find 1 , +.Xr chdir 2 , +.Xr stat 2 , +.Xr ftw 3 , +.Xr qsort 3 +.Sh HISTORY +The +.Nm +interface was first introduced in +.Bx 4.4 . +The +.Fn fts_get_clientptr , +.Fn fts_get_stream , +and +.Fn fts_set_clientptr +functions were introduced in +.Fx 5.0 , +principally to provide for alternative interfaces to the +.Nm +functionality using different data structures. +Blocks support and the +.Dv FTS_COMFOLLOWDIR +and +.Dv FTS_NOSTAT +options were added in +.Fx 15.0 +based on similar functionality in macOS. +.Sh BUGS +The +.Fn fts_open +function will automatically set the +.Dv FTS_NOCHDIR +option if the +.Dv FTS_LOGICAL +option is provided, or if it cannot +.Xr open 2 +the current directory. diff --git a/lib/libc/gen/fts.c b/lib/libc/gen/fts.c new file mode 100644 index 000000000000..4aa386d777cd --- /dev/null +++ b/lib/libc/gen/fts.c @@ -0,0 +1,1306 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $OpenBSD: fts.c,v 1.22 1999/10/03 19:22:22 millert Exp $ + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <fts.h> +#include <stdalign.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "gen-private.h" + +#ifdef __BLOCKS__ +#include <Block.h> +#else +#include "block_abi.h" +typedef DECLARE_BLOCK(int, fts_block, + const FTSENT * const *, const FTSENT * const *); +void qsort_b(void *, size_t, size_t, fts_block); +#endif /* __BLOCKS__ */ +/* only present if linked with blocks runtime */ +void *_Block_copy(const void *) __weak_symbol; +void _Block_release(const void *) __weak_symbol; +extern void *_NSConcreteGlobalBlock[] __weak_symbol; + +static FTSENT *fts_alloc(FTS *, char *, size_t); +static FTSENT *fts_build(FTS *, int); +static void fts_lfree(FTSENT *); +static void fts_load(FTS *, FTSENT *); +static size_t fts_maxarglen(char * const *); +static void fts_padjust(FTS *, FTSENT *); +static int fts_palloc(FTS *, size_t); +static FTSENT *fts_sort(FTS *, FTSENT *, size_t); +static int fts_stat(FTS *, FTSENT *, int, int); +static int fts_safe_changedir(FTS *, FTSENT *, int, char *); +static int fts_ufslinks(FTS *, const FTSENT *); + +#define ISDOT(a) (a[0] == '.' && (!a[1] || (a[1] == '.' && !a[2]))) + +#define CLR(opt) (sp->fts_options &= ~(opt)) +#define ISSET(opt) (sp->fts_options & (opt)) +#define SET(opt) (sp->fts_options |= (opt)) + +#define FCHDIR(sp, fd) (!ISSET(FTS_NOCHDIR) && fchdir(fd)) + +/* fts_build flags */ +#define BCHILD 1 /* fts_children */ +#define BNAMES 2 /* fts_children, names only */ +#define BREAD 3 /* fts_read */ + +/* + * Internal representation of an FTS, including extra implementation + * details. The FTS returned from fts_open points to this structure's + * ftsp_fts member (and can be cast to an _fts_private as required) + */ +struct _fts_private { + FTS ftsp_fts; + struct statfs ftsp_statfs; + dev_t ftsp_dev; + int ftsp_linksreliable; +}; + +/* + * The "FTS_NOSTAT" option can avoid a lot of calls to stat(2) if it + * knows that a directory could not possibly have subdirectories. This + * is decided by looking at the link count: a subdirectory would + * increment its parent's link count by virtue of its own ".." entry. + * This assumption only holds for UFS-like filesystems that implement + * links and directories this way, so we must punt for others. + */ +static const char *ufslike_filesystems[] = { + "ufs", + "zfs", + "nfs", + "ext2fs", + 0 +}; + +static FTS * +__fts_open(FTS *sp, char * const *argv) +{ + FTSENT *p, *root; + FTSENT *parent, *tmp; + size_t len, nitems; + + /* Logical walks turn on NOCHDIR; symbolic links are too hard. */ + if (ISSET(FTS_LOGICAL)) + SET(FTS_NOCHDIR); + + /* NOSTAT_TYPE implies NOSTAT */ + if (ISSET(FTS_NOSTAT_TYPE)) + SET(FTS_NOSTAT); + + /* + * Start out with 1K of path space, and enough, in any case, + * to hold the user's paths. + */ + if (fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN))) + goto mem1; + + /* Allocate/initialize root's parent. */ + if ((parent = fts_alloc(sp, "", 0)) == NULL) + goto mem2; + parent->fts_level = FTS_ROOTPARENTLEVEL; + + /* Shush, GCC. */ + tmp = NULL; + + /* Allocate/initialize root(s). */ + for (root = NULL, nitems = 0; *argv != NULL; ++argv, ++nitems) { + len = strlen(*argv); + + p = fts_alloc(sp, *argv, len); + p->fts_level = FTS_ROOTLEVEL; + p->fts_parent = parent; + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, + ISSET(FTS_COMFOLLOWDIR) ? -1 : ISSET(FTS_COMFOLLOW), + -1); + + /* Command-line "." and ".." are real directories. */ + if (p->fts_info == FTS_DOT) + p->fts_info = FTS_D; + + /* + * If comparison routine supplied, traverse in sorted + * order; otherwise traverse in the order specified. + */ + if (sp->fts_compar) { + p->fts_link = root; + root = p; + } else { + p->fts_link = NULL; + if (root == NULL) + tmp = root = p; + else { + tmp->fts_link = p; + tmp = p; + } + } + } + if (sp->fts_compar && nitems > 1) + root = fts_sort(sp, root, nitems); + + /* + * Allocate a dummy pointer and make fts_read think that we've just + * finished the node before the root(s); set p->fts_info to FTS_INIT + * so that everything about the "current" node is ignored. + */ + if ((sp->fts_cur = fts_alloc(sp, "", 0)) == NULL) + goto mem3; + sp->fts_cur->fts_link = root; + sp->fts_cur->fts_info = FTS_INIT; + + /* + * If using chdir(2), grab a file descriptor pointing to dot to ensure + * that we can get back here; this could be avoided for some paths, + * but almost certainly not worth the effort. Slashes, symbolic links, + * and ".." are all fairly nasty problems. Note, if we can't get the + * descriptor we run anyway, just more slowly. + */ + if (!ISSET(FTS_NOCHDIR) && + (sp->fts_rfd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + SET(FTS_NOCHDIR); + + return (sp); + +mem3: fts_lfree(root); + free(parent); +mem2: free(sp->fts_path); +mem1: free(sp); + return (NULL); +} + +FTS * +fts_open(char * const *argv, int options, + int (*compar)(const FTSENT * const *, const FTSENT * const *)) +{ + struct _fts_private *priv; + FTS *sp; + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; + sp->fts_compar = compar; + sp->fts_options = options; + + return (__fts_open(sp, argv)); +} + +#ifdef __BLOCKS__ +FTS * +fts_open_b(char * const *argv, int options, + int (^compar)(const FTSENT * const *, const FTSENT * const *)) +#else +FTS * +fts_open_b(char * const *argv, int options, fts_block compar) +#endif /* __BLOCKS__ */ +{ + struct _fts_private *priv; + FTS *sp; + + /* No blocks, no problems. */ + if (compar == NULL) + return (fts_open(argv, options, NULL)); + + /* Avoid segfault if blocks runtime is missing. */ + if (_Block_copy == NULL) { + errno = ENOSYS; + return (NULL); + } + + /* Options check. */ + if (options & ~FTS_OPTIONMASK) { + errno = EINVAL; + return (NULL); + } + + /* fts_open() requires at least one path */ + if (*argv == NULL) { + errno = EINVAL; + return (NULL); + } + + /* Allocate/initialize the stream. */ + if ((priv = calloc(1, sizeof(*priv))) == NULL) + return (NULL); + sp = &priv->ftsp_fts; +#ifdef __BLOCKS__ + compar = Block_copy(compar); +#else + if (compar->isa != &_NSConcreteGlobalBlock) + compar = _Block_copy(compar); +#endif /* __BLOCKS__ */ + if (compar == NULL) { + free(priv); + return (NULL); + } + sp->fts_compar_b = compar; + sp->fts_options = options | FTS_COMPAR_B; + + if ((sp = __fts_open(sp, argv)) == NULL) { +#ifdef __BLOCKS__ + Block_release(compar); +#else + if (compar->isa != &_NSConcreteGlobalBlock) + _Block_release(compar); +#endif /* __BLOCKS__ */ + } + return (sp); +} + +static void +fts_load(FTS *sp, FTSENT *p) +{ + size_t len; + char *cp; + + /* + * Load the stream structure for the next traversal. Since we don't + * actually enter the directory until after the preorder visit, set + * the fts_accpath field specially so the chdir gets done to the right + * place and the user can access the first node. From fts_open it's + * known that the path will fit. + */ + len = p->fts_pathlen = p->fts_namelen; + memmove(sp->fts_path, p->fts_name, len + 1); + if ((cp = strrchr(p->fts_name, '/')) && (cp != p->fts_name || cp[1])) { + len = strlen(++cp); + memmove(p->fts_name, cp, len + 1); + p->fts_namelen = len; + } + p->fts_accpath = p->fts_path = sp->fts_path; + sp->fts_dev = p->fts_dev; +} + +int +fts_close(FTS *sp) +{ + FTSENT *freep, *p; + int saved_errno; + + /* + * This still works if we haven't read anything -- the dummy structure + * points to the root list, so we step through to the end of the root + * list which has a valid parent pointer. + */ + if (sp->fts_cur) { + for (p = sp->fts_cur; p->fts_level >= FTS_ROOTLEVEL;) { + freep = p; + p = p->fts_link != NULL ? p->fts_link : p->fts_parent; + free(freep); + } + free(p); + } + + /* Free up child linked list, sort array, path buffer. */ + if (sp->fts_child) + fts_lfree(sp->fts_child); + if (sp->fts_array) + free(sp->fts_array); + free(sp->fts_path); + + /* Free up any block pointer. */ + if (ISSET(FTS_COMPAR_B) && sp->fts_compar_b != NULL) { +#ifdef __BLOCKS__ + Block_release(sp->fts_compar_b); +#else + if (((fts_block)(sp->fts_compar_b))->isa != + &_NSConcreteGlobalBlock) + _Block_release(sp->fts_compar_b); +#endif /* __BLOCKS__ */ + } + + /* Return to original directory, save errno if necessary. */ + if (!ISSET(FTS_NOCHDIR)) { + saved_errno = fchdir(sp->fts_rfd) ? errno : 0; + (void)_close(sp->fts_rfd); + + /* Set errno and return. */ + if (saved_errno != 0) { + /* Free up the stream pointer. */ + free(sp); + errno = saved_errno; + return (-1); + } + } + + /* Free up the stream pointer. */ + free(sp); + return (0); +} + +/* + * Special case of "/" at the end of the path so that slashes aren't + * appended which would cause paths to be written as "....//foo". + */ +#define NAPPEND(p) \ + (p->fts_path[p->fts_pathlen - 1] == '/' \ + ? p->fts_pathlen - 1 : p->fts_pathlen) + +FTSENT * +fts_read(FTS *sp) +{ + FTSENT *p, *tmp; + int instr; + char *t; + int saved_errno; + + /* If finished or unrecoverable error, return NULL. */ + if (sp->fts_cur == NULL || ISSET(FTS_STOP)) + return (NULL); + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* Save and zero out user instructions. */ + instr = p->fts_instr; + p->fts_instr = FTS_NOINSTR; + + /* Any type of file may be re-visited; re-stat and re-turn. */ + if (instr == FTS_AGAIN) { + p->fts_info = fts_stat(sp, p, 0, -1); + return (p); + } + + /* + * Following a symlink -- SLNONE test allows application to see + * SLNONE and recover. If indirecting through a symlink, have + * keep a pointer to current location. If unable to get that + * pointer, follow fails. + */ + if (instr == FTS_FOLLOW && + (p->fts_info == FTS_SL || p->fts_info == FTS_SLNONE)) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = _open(".", O_RDONLY | O_CLOEXEC, + 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + return (p); + } + + /* Directory in pre-order. */ + if (p->fts_info == FTS_D) { + /* If skipped or crossed mount point, do post-order visit. */ + if (instr == FTS_SKIP || + (ISSET(FTS_XDEV) && p->fts_dev != sp->fts_dev)) { + if (p->fts_flags & FTS_SYMFOLLOW) + (void)_close(p->fts_symfd); + if (sp->fts_child) { + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + p->fts_info = FTS_DP; + return (p); + } + + /* Rebuild if only read the names and now traversing. */ + if (sp->fts_child != NULL && ISSET(FTS_NAMEONLY)) { + CLR(FTS_NAMEONLY); + fts_lfree(sp->fts_child); + sp->fts_child = NULL; + } + + /* + * Cd to the subdirectory. + * + * If have already read and now fail to chdir, whack the list + * to make the names come out right, and set the parent errno + * so the application will eventually get an error condition. + * Set the FTS_DONTCHDIR flag so that when we logically change + * directories back to the parent we don't do a chdir. + * + * If haven't read do so. If the read fails, fts_build sets + * FTS_STOP or the fts_info field of the node. + */ + if (sp->fts_child != NULL) { + if (fts_safe_changedir(sp, p, -1, p->fts_accpath)) { + p->fts_errno = errno; + p->fts_flags |= FTS_DONTCHDIR; + for (p = sp->fts_child; p != NULL; + p = p->fts_link) + p->fts_accpath = + p->fts_parent->fts_accpath; + } + } else if ((sp->fts_child = fts_build(sp, BREAD)) == NULL) { + if (ISSET(FTS_STOP)) + return (NULL); + return (p); + } + p = sp->fts_child; + sp->fts_child = NULL; + goto name; + } + + /* Move to the next node on this level. */ +next: tmp = p; + if ((p = p->fts_link) != NULL) { + /* + * If reached the top, return to the original directory (or + * the root of the tree), and load the paths for the next root. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + free(tmp); + fts_load(sp, p); + return (sp->fts_cur = p); + } + + /* + * User may have called fts_set on the node. If skipped, + * ignore. If followed, get a file descriptor so we can + * get back if necessary. + */ + if (p->fts_instr == FTS_SKIP) { + free(tmp); + goto next; + } + if (p->fts_instr == FTS_FOLLOW) { + p->fts_info = fts_stat(sp, p, 1, -1); + if (p->fts_info == FTS_D && !ISSET(FTS_NOCHDIR)) { + if ((p->fts_symfd = + _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) { + p->fts_errno = errno; + p->fts_info = FTS_ERR; + } else + p->fts_flags |= FTS_SYMFOLLOW; + } + p->fts_instr = FTS_NOINSTR; + } + + free(tmp); + +name: t = sp->fts_path + NAPPEND(p->fts_parent); + *t++ = '/'; + memmove(t, p->fts_name, p->fts_namelen + 1); + return (sp->fts_cur = p); + } + + /* Move up to the parent node. */ + p = tmp->fts_parent; + + if (p->fts_level == FTS_ROOTPARENTLEVEL) { + /* + * Done; free everything up and set errno to 0 so the user + * can distinguish between error and EOF. + */ + free(tmp); + free(p); + errno = 0; + return (sp->fts_cur = NULL); + } + + /* NUL terminate the pathname. */ + sp->fts_path[p->fts_pathlen] = '\0'; + + /* + * Return to the parent directory. If at a root node or came through + * a symlink, go back through the file descriptor. Otherwise, cd up + * one directory. + */ + if (p->fts_level == FTS_ROOTLEVEL) { + if (FCHDIR(sp, sp->fts_rfd)) { + SET(FTS_STOP); + return (NULL); + } + } else if (p->fts_flags & FTS_SYMFOLLOW) { + if (FCHDIR(sp, p->fts_symfd)) { + saved_errno = errno; + (void)_close(p->fts_symfd); + errno = saved_errno; + SET(FTS_STOP); + return (NULL); + } + (void)_close(p->fts_symfd); + } else if (!(p->fts_flags & FTS_DONTCHDIR) && + fts_safe_changedir(sp, p->fts_parent, -1, "..")) { + SET(FTS_STOP); + return (NULL); + } + free(tmp); + p->fts_info = p->fts_errno ? FTS_ERR : FTS_DP; + return (sp->fts_cur = p); +} + +/* + * Fts_set takes the stream as an argument although it's not used in this + * implementation; it would be necessary if anyone wanted to add global + * semantics to fts using fts_set. An error return is allowed for similar + * reasons. + */ +/* ARGSUSED */ +int +fts_set(FTS *sp, FTSENT *p, int instr) +{ + if (instr != 0 && instr != FTS_AGAIN && instr != FTS_FOLLOW && + instr != FTS_NOINSTR && instr != FTS_SKIP) { + errno = EINVAL; + return (1); + } + p->fts_instr = instr; + return (0); +} + +FTSENT * +fts_children(FTS *sp, int instr) +{ + FTSENT *p; + int fd, rc, serrno; + + if (instr != 0 && instr != FTS_NAMEONLY) { + errno = EINVAL; + return (NULL); + } + + /* Set current node pointer. */ + p = sp->fts_cur; + + /* + * Errno set to 0 so user can distinguish empty directory from + * an error. + */ + errno = 0; + + /* Fatal errors stop here. */ + if (ISSET(FTS_STOP)) + return (NULL); + + /* Return logical hierarchy of user's arguments. */ + if (p->fts_info == FTS_INIT) + return (p->fts_link); + + /* + * If not a directory being visited in pre-order, stop here. Could + * allow FTS_DNR, assuming the user has fixed the problem, but the + * same effect is available with FTS_AGAIN. + */ + if (p->fts_info != FTS_D /* && p->fts_info != FTS_DNR */) + return (NULL); + + /* Free up any previous child list. */ + if (sp->fts_child != NULL) + fts_lfree(sp->fts_child); + + if (instr == FTS_NAMEONLY) { + SET(FTS_NAMEONLY); + instr = BNAMES; + } else + instr = BCHILD; + + /* + * If using chdir on a relative path and called BEFORE fts_read does + * its chdir to the root of a traversal, we can lose -- we need to + * chdir into the subdirectory, and we don't know where the current + * directory is, so we can't get back so that the upcoming chdir by + * fts_read will work. + */ + if (p->fts_level != FTS_ROOTLEVEL || p->fts_accpath[0] == '/' || + ISSET(FTS_NOCHDIR)) + return (sp->fts_child = fts_build(sp, instr)); + + if ((fd = _open(".", O_RDONLY | O_CLOEXEC, 0)) < 0) + return (NULL); + sp->fts_child = fts_build(sp, instr); + serrno = (sp->fts_child == NULL) ? errno : 0; + rc = fchdir(fd); + if (rc < 0 && serrno == 0) + serrno = errno; + (void)_close(fd); + errno = serrno; + if (rc < 0) + return (NULL); + return (sp->fts_child); +} + +#ifndef fts_get_clientptr +#error "fts_get_clientptr not defined" +#endif + +void * +(fts_get_clientptr)(FTS *sp) +{ + return (fts_get_clientptr(sp)); +} + +#ifndef fts_get_stream +#error "fts_get_stream not defined" +#endif + +FTS * +(fts_get_stream)(FTSENT *p) +{ + return (fts_get_stream(p)); +} + +void +fts_set_clientptr(FTS *sp, void *clientptr) +{ + sp->fts_clientptr = clientptr; +} + +static struct dirent * +fts_safe_readdir(DIR *dirp, int *readdir_errno) +{ + struct dirent *ret; + + errno = 0; + if (!dirp) + return (NULL); + ret = readdir(dirp); + *readdir_errno = errno; + return (ret); +} + +/* + * This is the tricky part -- do not casually change *anything* in here. The + * idea is to build the linked list of entries that are used by fts_children + * and fts_read. There are lots of special cases. + * + * The real slowdown in walking the tree is the stat calls. If FTS_NOSTAT is + * set and it's a physical walk (so that symbolic links can't be directories), + * we can do things quickly. First, if it's a 4.4BSD file system, the type + * of the file is in the directory entry. Otherwise, we assume that the number + * of subdirectories in a node is equal to the number of links to the parent. + * The former skips all stat calls. The latter skips stat calls in any leaf + * directories and for any files after the subdirectories in the directory have + * been found, cutting the stat calls by about 2/3. + */ +static FTSENT * +fts_build(FTS *sp, int type) +{ + struct dirent *dp; + FTSENT *p, *head; + FTSENT *cur, *tail; + DIR *dirp; + void *oldaddr; + char *cp; + int cderrno, descend, oflag, saved_errno, nostat, doadjust, + readdir_errno; + long level; + long nlinks; /* has to be signed because -1 is a magic value */ + size_t dnamlen, len, maxlen, nitems; + + /* Set current node pointer. */ + cur = sp->fts_cur; + + /* + * Open the directory for reading. If this fails, we're done. + * If being called from fts_read, set the fts_info field. + */ + if (ISSET(FTS_WHITEOUT)) + oflag = DTF_NODUP; + else + oflag = DTF_HIDEW | DTF_NODUP; + if ((dirp = __opendir2(cur->fts_accpath, oflag)) == NULL) { + if (type == BREAD) { + cur->fts_info = FTS_DNR; + cur->fts_errno = errno; + } + return (NULL); + } + + /* + * Nlinks is the number of possible entries of type directory in the + * directory if we're cheating on stat calls, 0 if we're not doing + * any stat calls at all, -1 if we're doing stats on everything. + */ + if (type == BNAMES) { + nlinks = 0; + /* Be quiet about nostat, GCC. */ + nostat = 0; + } else if (ISSET(FTS_NOSTAT) && ISSET(FTS_PHYSICAL)) { + if (fts_ufslinks(sp, cur)) + nlinks = cur->fts_nlink - (ISSET(FTS_SEEDOT) ? 0 : 2); + else + nlinks = -1; + nostat = 1; + } else { + nlinks = -1; + nostat = 0; + } + +#ifdef notdef + (void)printf("nlinks == %d (cur: %d)\n", nlinks, cur->fts_nlink); + (void)printf("NOSTAT %d PHYSICAL %d SEEDOT %d\n", + ISSET(FTS_NOSTAT), ISSET(FTS_PHYSICAL), ISSET(FTS_SEEDOT)); +#endif + /* + * If we're going to need to stat anything or we want to descend + * and stay in the directory, chdir. If this fails we keep going, + * but set a flag so we don't chdir after the post-order visit. + * We won't be able to stat anything, but we can still return the + * names themselves. Note, that since fts_read won't be able to + * chdir into the directory, it will have to return different path + * names than before, i.e. "a/b" instead of "b". Since the node + * has already been visited in pre-order, have to wait until the + * post-order visit to return the error. There is a special case + * here, if there was nothing to stat then it's not an error to + * not be able to stat. This is all fairly nasty. If a program + * needed sorted entries or stat information, they had better be + * checking FTS_NS on the returned nodes. + */ + cderrno = 0; + if (nlinks || type == BREAD) { + if (fts_safe_changedir(sp, cur, _dirfd(dirp), NULL)) { + if (nlinks && type == BREAD) + cur->fts_errno = errno; + cur->fts_flags |= FTS_DONTCHDIR; + descend = 0; + cderrno = errno; + } else + descend = 1; + } else + descend = 0; + + /* + * Figure out the max file name length that can be stored in the + * current path -- the inner loop allocates more path as necessary. + * We really wouldn't have to do the maxlen calculations here, we + * could do them in fts_read before returning the path, but it's a + * lot easier here since the length is part of the dirent structure. + * + * If not changing directories set a pointer so that can just append + * each new name into the path. + */ + len = NAPPEND(cur); + if (ISSET(FTS_NOCHDIR)) { + cp = sp->fts_path + len; + *cp++ = '/'; + } else { + /* GCC, you're too verbose. */ + cp = NULL; + } + len++; + maxlen = sp->fts_pathlen - len; + + level = cur->fts_level + 1; + + /* Read the directory, attaching each entry to the `link' pointer. */ + doadjust = 0; + readdir_errno = 0; + for (head = tail = NULL, nitems = 0; + (dp = fts_safe_readdir(dirp, &readdir_errno));) { + dnamlen = dp->d_namlen; + if (!ISSET(FTS_SEEDOT) && ISDOT(dp->d_name)) + continue; + + if ((p = fts_alloc(sp, dp->d_name, dnamlen)) == NULL) + goto mem1; + if (dnamlen >= maxlen) { /* include space for NUL */ + oldaddr = sp->fts_path; + if (fts_palloc(sp, dnamlen + len + 1)) { + /* + * No more memory for path or structures. Save + * errno, free up the current structure and the + * structures already allocated. + */ +mem1: saved_errno = errno; + if (p) + free(p); + fts_lfree(head); + (void)closedir(dirp); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + errno = saved_errno; + return (NULL); + } + /* Did realloc() change the pointer? */ + if (oldaddr != sp->fts_path) { + doadjust = 1; + if (ISSET(FTS_NOCHDIR)) + cp = sp->fts_path + len; + } + maxlen = sp->fts_pathlen - len; + } + + p->fts_level = level; + p->fts_parent = sp->fts_cur; + p->fts_pathlen = len + dnamlen; + + if (dp->d_type == DT_WHT) + p->fts_flags |= FTS_ISW; + + if (cderrno) { + if (nlinks) { + p->fts_info = FTS_NS; + p->fts_errno = cderrno; + } else + p->fts_info = FTS_NSOK; + p->fts_accpath = cur->fts_accpath; + } else if (nlinks == 0 || (nostat && + dp->d_type != DT_DIR && dp->d_type != DT_UNKNOWN)) { + p->fts_accpath = + ISSET(FTS_NOCHDIR) ? p->fts_path : p->fts_name; + p->fts_info = FTS_NSOK; + } else { + /* Build a file name for fts_stat to stat. */ + if (ISSET(FTS_NOCHDIR)) { + p->fts_accpath = p->fts_path; + memmove(cp, p->fts_name, p->fts_namelen + 1); + p->fts_info = fts_stat(sp, p, 0, _dirfd(dirp)); + } else { + p->fts_accpath = p->fts_name; + p->fts_info = fts_stat(sp, p, 0, -1); + } + + /* Decrement link count if applicable. */ + if (nlinks > 0 && (p->fts_info == FTS_D || + p->fts_info == FTS_DC || p->fts_info == FTS_DOT)) + --nlinks; + } + if (p->fts_info == FTS_NSOK && ISSET(FTS_NOSTAT_TYPE)) { + switch (dp->d_type) { + case DT_FIFO: + case DT_CHR: + case DT_BLK: + case DT_SOCK: + p->fts_info = FTS_DEFAULT; + break; + case DT_REG: + p->fts_info = FTS_F; + break; + case DT_LNK: + p->fts_info = FTS_SL; + break; + case DT_WHT: + p->fts_info = FTS_W; + break; + } + } + + /* We walk in directory order so "ls -f" doesn't get upset. */ + p->fts_link = NULL; + if (head == NULL) + head = tail = p; + else { + tail->fts_link = p; + tail = p; + } + ++nitems; + } + + if (readdir_errno) { + cur->fts_errno = readdir_errno; + /* + * If we've not read any items yet, treat + * the error as if we can't access the dir. + */ + cur->fts_info = nitems ? FTS_ERR : FTS_DNR; + } + + if (dirp) + (void)closedir(dirp); + + /* + * If realloc() changed the address of the path, adjust the + * addresses for the rest of the tree and the dir list. + */ + if (doadjust) + fts_padjust(sp, head); + + /* + * If not changing directories, reset the path back to original + * state. + */ + if (ISSET(FTS_NOCHDIR)) + sp->fts_path[cur->fts_pathlen] = '\0'; + + /* + * If descended after called from fts_children or after called from + * fts_read and nothing found, get back. At the root level we use + * the saved fd; if one of fts_open()'s arguments is a relative path + * to an empty directory, we wind up here with no other way back. If + * can't get back, we're done. + */ + if (descend && (type == BCHILD || !nitems) && + (cur->fts_level == FTS_ROOTLEVEL ? + FCHDIR(sp, sp->fts_rfd) : + fts_safe_changedir(sp, cur->fts_parent, -1, ".."))) { + fts_lfree(head); + cur->fts_info = FTS_ERR; + SET(FTS_STOP); + return (NULL); + } + + /* If didn't find anything, return NULL. */ + if (!nitems) { + if (type == BREAD && + cur->fts_info != FTS_DNR && cur->fts_info != FTS_ERR) + cur->fts_info = FTS_DP; + return (NULL); + } + + /* Sort the entries. */ + if (sp->fts_compar && nitems > 1) + head = fts_sort(sp, head, nitems); + return (head); +} + +static int +fts_stat(FTS *sp, FTSENT *p, int follow, int dfd) +{ + FTSENT *t; + dev_t dev; + ino_t ino; + struct stat *sbp, sb; + int ret, saved_errno; + const char *path; + + if (dfd == -1) { + path = p->fts_accpath; + dfd = AT_FDCWD; + } else { + path = p->fts_name; + } + + /* If user needs stat info, stat buffer already allocated. */ + sbp = ISSET(FTS_NOSTAT) ? &sb : p->fts_statp; + + /* Check for whiteout. */ + if (p->fts_flags & FTS_ISW) { + if (sbp != &sb) { + memset(sbp, '\0', sizeof(*sbp)); + sbp->st_mode = S_IFWHT; + } + return (FTS_W); + } + + /* + * If doing a logical walk, or caller requested FTS_COMFOLLOW, do + * a full stat(2). If that fails, do an lstat(2) to check for a + * non-existent symlink. If that fails, set the errno from the + * stat(2) call. + * + * As a special case, if stat(2) succeeded but the target is not a + * directory and follow is negative (indicating FTS_COMFOLLOWDIR + * rather than FTS_COMFOLLOW), we also revert to lstat(2). + */ + if (ISSET(FTS_LOGICAL) || follow) { + if ((ret = fstatat(dfd, path, sbp, 0)) != 0 || + (follow < 0 && !S_ISDIR(sbp->st_mode))) { + saved_errno = errno; + if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = saved_errno; + goto err; + } + errno = 0; + if (ret != 0 && S_ISLNK(sbp->st_mode)) + return (FTS_SLNONE); + } + } else if (fstatat(dfd, path, sbp, AT_SYMLINK_NOFOLLOW)) { + p->fts_errno = errno; +err: memset(sbp, 0, sizeof(struct stat)); + return (FTS_NS); + } + + if (S_ISDIR(sbp->st_mode)) { + /* + * Set the device/inode. Used to find cycles and check for + * crossing mount points. Also remember the link count, used + * in fts_build to limit the number of stat calls. It is + * understood that these fields are only referenced if fts_info + * is set to FTS_D. + */ + dev = p->fts_dev = sbp->st_dev; + ino = p->fts_ino = sbp->st_ino; + p->fts_nlink = sbp->st_nlink; + + if (ISDOT(p->fts_name)) + return (FTS_DOT); + + /* + * Cycle detection is done by brute force when the directory + * is first encountered. If the tree gets deep enough or the + * number of symbolic links to directories is high enough, + * something faster might be worthwhile. + */ + for (t = p->fts_parent; + t->fts_level >= FTS_ROOTLEVEL; t = t->fts_parent) + if (ino == t->fts_ino && dev == t->fts_dev) { + p->fts_cycle = t; + return (FTS_DC); + } + return (FTS_D); + } + if (S_ISLNK(sbp->st_mode)) + return (FTS_SL); + if (S_ISREG(sbp->st_mode)) + return (FTS_F); + return (FTS_DEFAULT); +} + +static FTSENT * +fts_sort(FTS *sp, FTSENT *head, size_t nitems) +{ + FTSENT **ap, *p; + + /* + * Construct an array of pointers to the structures and call qsort(3). + * Reassemble the array in the order returned by qsort. If unable to + * sort for memory reasons, return the directory entries in their + * current order. Allocate enough space for the current needs plus + * 40 so don't realloc one entry at a time. + */ + if (nitems > sp->fts_nitems) { + sp->fts_nitems = nitems + 40; + if ((sp->fts_array = reallocf(sp->fts_array, + sp->fts_nitems * sizeof(FTSENT *))) == NULL) { + sp->fts_nitems = 0; + return (head); + } + } + for (ap = sp->fts_array, p = head; p; p = p->fts_link) + *ap++ = p; + if (ISSET(FTS_COMPAR_B)) { +#ifdef __BLOCKS__ + qsort_b(sp->fts_array, nitems, sizeof(FTSENT *), + (int (^)(const void *, const void *))sp->fts_compar_b); +#else + qsort_b(sp->fts_array, nitems, sizeof(FTSENT *), + sp->fts_compar_b); +#endif /* __BLOCKS__ */ + } else { + qsort(sp->fts_array, nitems, sizeof(FTSENT *), + (int (*)(const void *, const void *))sp->fts_compar); + } + for (head = *(ap = sp->fts_array); --nitems; ++ap) + ap[0]->fts_link = ap[1]; + ap[0]->fts_link = NULL; + return (head); +} + +static FTSENT * +fts_alloc(FTS *sp, char *name, size_t namelen) +{ + FTSENT *p; + size_t len; + + /* + * The file name is a variable length array and no stat structure is + * necessary if the user has set the nostat bit. Allocate the FTSENT + * structure, the file name and the stat structure in one chunk, but + * be careful that the stat structure is reasonably aligned. + */ + len = sizeof(FTSENT) + namelen + 1; + if (!ISSET(FTS_NOSTAT)) { + len = roundup(len, alignof(struct stat)); + p = calloc(1, len + sizeof(struct stat)); + } else { + p = calloc(1, len); + } + if (p == NULL) + return (NULL); + + p->fts_symfd = -1; + p->fts_path = sp->fts_path; + p->fts_name = (char *)(p + 1); + p->fts_namelen = namelen; + p->fts_instr = FTS_NOINSTR; + if (!ISSET(FTS_NOSTAT)) + p->fts_statp = (struct stat *)((char *)p + len); + p->fts_fts = sp; + memcpy(p->fts_name, name, namelen); + + return (p); +} + +static void +fts_lfree(FTSENT *head) +{ + FTSENT *p; + + /* Free a linked list of structures. */ + while ((p = head)) { + head = head->fts_link; + free(p); + } +} + +/* + * Allow essentially unlimited paths; find, rm, ls should all work on any tree. + * Most systems will allow creation of paths much longer than MAXPATHLEN, even + * though the kernel won't resolve them. Add the size (not just what's needed) + * plus 256 bytes so don't realloc the path 2 bytes at a time. + */ +static int +fts_palloc(FTS *sp, size_t more) +{ + + sp->fts_pathlen += more + 256; + sp->fts_path = reallocf(sp->fts_path, sp->fts_pathlen); + return (sp->fts_path == NULL); +} + +/* + * When the path is realloc'd, have to fix all of the pointers in structures + * already returned. + */ +static void +fts_padjust(FTS *sp, FTSENT *head) +{ + FTSENT *p; + char *addr = sp->fts_path; + +#define ADJUST(p) do { \ + if ((p)->fts_accpath != (p)->fts_name) { \ + (p)->fts_accpath = \ + (char *)addr + ((p)->fts_accpath - (p)->fts_path); \ + } \ + (p)->fts_path = addr; \ +} while (0) + /* Adjust the current set of children. */ + for (p = sp->fts_child; p; p = p->fts_link) + ADJUST(p); + + /* Adjust the rest of the tree, including the current level. */ + for (p = head; p->fts_level >= FTS_ROOTLEVEL;) { + ADJUST(p); + p = p->fts_link ? p->fts_link : p->fts_parent; + } +} + +static size_t +fts_maxarglen(char * const *argv) +{ + size_t len, max; + + for (max = 0; *argv; ++argv) + if ((len = strlen(*argv)) > max) + max = len; + return (max + 1); +} + +/* + * Change to dir specified by fd or p->fts_accpath without getting + * tricked by someone changing the world out from underneath us. + * Assumes p->fts_dev and p->fts_ino are filled in. + */ +static int +fts_safe_changedir(FTS *sp, FTSENT *p, int fd, char *path) +{ + int ret, oerrno, newfd; + struct stat sb; + struct statfs sf; + + newfd = fd; + if (ISSET(FTS_NOCHDIR)) + return (0); + if (fd < 0 && (newfd = _open(path, O_RDONLY | O_DIRECTORY | + O_CLOEXEC, 0)) < 0) + return (-1); + if (_fstat(newfd, &sb)) { + ret = -1; + goto bail; + } + if (p->fts_dev != sb.st_dev || p->fts_ino != sb.st_ino) { + if (_fstatfs(newfd, &sf) != 0 || + (sf.f_flags & MNT_AUTOMOUNTED) == 0) { + errno = ENOENT; /* disinformation */ + ret = -1; + goto bail; + } + /* autofs might did the mount under us, accept. */ + p->fts_dev = sb.st_dev; + p->fts_ino = sb.st_ino; + } + ret = fchdir(newfd); +bail: + oerrno = errno; + if (fd < 0) + (void)_close(newfd); + errno = oerrno; + return (ret); +} + +/* + * Check if the filesystem for "ent" has UFS-style links. + */ +static int +fts_ufslinks(FTS *sp, const FTSENT *ent) +{ + struct _fts_private *priv; + const char **cpp; + + priv = (struct _fts_private *)sp; + /* + * If this node's device is different from the previous, grab + * the filesystem information, and decide on the reliability + * of the link information from this filesystem for stat(2) + * avoidance. + */ + if (priv->ftsp_dev != ent->fts_dev) { + if (statfs(ent->fts_path, &priv->ftsp_statfs) != -1) { + priv->ftsp_dev = ent->fts_dev; + priv->ftsp_linksreliable = 0; + for (cpp = ufslike_filesystems; *cpp; cpp++) { + if (strcmp(priv->ftsp_statfs.f_fstypename, + *cpp) == 0) { + priv->ftsp_linksreliable = 1; + break; + } + } + } else { + priv->ftsp_linksreliable = 0; + } + } + return (priv->ftsp_linksreliable); +} diff --git a/lib/libc/gen/ftw-compat11.c b/lib/libc/gen/ftw-compat11.c new file mode 100644 index 000000000000..28d6398f6fd8 --- /dev/null +++ b/lib/libc/gen/ftw-compat11.c @@ -0,0 +1,98 @@ +/* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */ + +/* + * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + * + * From: FreeBSD: head/lib/libc/gen/ftw.c 239151 2012-08-09 15:11:38Z jilles + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fts.h> +#include <ftw.h> + +#include "fts-compat11.h" + +int freebsd11_ftw(const char *path, int (*fn)(const char *, + const struct freebsd11_stat *, int), int nfds); + +int +freebsd11_ftw(const char *path, + int (*fn)(const char *, const struct freebsd11_stat *, int), int nfds) +{ + char * const paths[2] = { (char *)path, NULL }; + FTSENT11 *cur; + FTS11 *ftsp; + int error = 0, fnflag, sverrno; + + /* XXX - nfds is currently unused */ + if (nfds < 1) { + errno = EINVAL; + return (-1); + } + + ftsp = freebsd11_fts_open(paths, + FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL); + if (ftsp == NULL) + return (-1); + while ((cur = freebsd11_fts_read(ftsp)) != NULL) { + switch (cur->fts_info) { + case FTS_D: + fnflag = FTW_D; + break; + case FTS_DNR: + fnflag = FTW_DNR; + break; + case FTS_DP: + /* we only visit in preorder */ + continue; + case FTS_F: + case FTS_DEFAULT: + fnflag = FTW_F; + break; + case FTS_NS: + case FTS_NSOK: + case FTS_SLNONE: + fnflag = FTW_NS; + break; + case FTS_SL: + fnflag = FTW_SL; + break; + case FTS_DC: + errno = ELOOP; + /* FALLTHROUGH */ + default: + error = -1; + goto done; + } + error = fn(cur->fts_path, cur->fts_statp, fnflag); + if (error != 0) + break; + } +done: + sverrno = errno; + if (freebsd11_fts_close(ftsp) != 0 && error == 0) + error = -1; + else + errno = sverrno; + return (error); +} + +__sym_compat(ftw, freebsd11_ftw, FBSD_1.0); diff --git a/lib/libc/gen/ftw.3 b/lib/libc/gen/ftw.3 new file mode 100644 index 000000000000..c9a1d6f1eee9 --- /dev/null +++ b/lib/libc/gen/ftw.3 @@ -0,0 +1,276 @@ +.\" $OpenBSD: ftw.3,v 1.5 2004/01/25 14:48:32 jmc Exp $ +.\" +.\" Copyright (c) 2003 Todd C. Miller <Todd.Miller@courtesan.com> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" Sponsored in part by the Defense Advanced Research Projects +.\" Agency (DARPA) and Air Force Research Laboratory, Air Force +.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. +.\" +.Dd March 12, 2020 +.Dt FTW 3 +.Os +.Sh NAME +.Nm ftw , nftw +.Nd traverse (walk) a file tree +.Sh SYNOPSIS +.In ftw.h +.Ft int +.Fo ftw +.Fa "const char *path" +.Fa "int \*[lp]*fn\*[rp]\*[lp]const char *, const struct stat *, int\*[rp]" +.Fa "int maxfds" +.Fc +.Ft int +.Fo nftw +.Fa "const char *path" +.Fa "int \*[lp]*fn\*[rp]\*[lp]const char *, const struct stat *, int, struct FTW *\*[rp]" +.Fa "int maxfds" +.Fa "int flags" +.Fc +.Sh DESCRIPTION +The +.Fn ftw +and +.Fn nftw +functions traverse (walk) the directory hierarchy rooted in +.Fa path . +For each object in the hierarchy, these functions call the function +pointed to by +.Fa fn . +The +.Fn ftw +function passes this function a pointer to a +.Dv NUL Ns +-terminated string containing +the name of the object, a pointer to a +.Vt stat +structure corresponding to the +object, and an integer flag. +The +.Fn nftw +function passes the aforementioned arguments plus a pointer to a +.Vt FTW +structure as defined by +.In ftw.h +(shown below): +.Bd -literal +struct FTW { + int base; /* offset of basename into pathname */ + int level; /* directory depth relative to starting point */ +}; +.Ed +.Pp +Possible values for the flag passed to +.Fa fn +are: +.Bl -tag -width ".Dv FTW_DNR" +.It Dv FTW_F +A regular file. +.It Dv FTW_D +A directory being visited in pre-order. +.It Dv FTW_DNR +A directory which cannot be read. +The directory will not be descended into. +.It Dv FTW_DP +A directory being visited in post-order +.Po Fn nftw +only +.Pc . +.It Dv FTW_NS +A file for which no +.Xr stat 2 +information was available. +The contents of the +.Vt stat +structure are undefined. +.It Dv FTW_SL +A symbolic link. +.It Dv FTW_SLN +A symbolic link with a non-existent target +.Po Fn nftw +only +.Pc . +.El +.Pp +The +.Fn ftw +function traverses the tree in pre-order. +That is, it processes the directory before the directory's contents. +.Pp +The +.Fa maxfds +argument specifies the maximum number of file descriptors +to keep open while traversing the tree. +It has no effect in this implementation. +.Pp +The +.Fn nftw +function has an additional +.Fa flags +argument with the following possible values: +.Bl -tag -width ".Dv FTW_MOUNT" +.It Dv FTW_PHYS +Physical walk, do not follow symbolic links. +.It Dv FTW_MOUNT +The walk will not cross a mount point. +.It FTW_DEPTH +Process directories in post-order. +Contents of a directory are visited before the directory itself. +By default, +.Fn nftw +traverses the tree in pre-order. +.It FTW_CHDIR +Change to a directory before reading it. +By default, +.Fn nftw +will change its starting directory. +The current working directory will be restored to its original value before +.Fn nftw +returns. +.El +.Sh RETURN VALUES +If the tree was traversed successfully, the +.Fn ftw +and +.Fn nftw +functions return 0. +If the function pointed to by +.Fa fn +returns a non-zero value, +.Fn ftw +and +.Fn nftw +will stop processing the tree and return the value from +.Fa fn . +Both functions return \-1 if an error is detected. +.Sh EXAMPLES +Following there is an example that shows how +.Nm nftw +can be used. +It traverses the file tree starting at the directory pointed +by the only program argument and shows the complete path and a brief +indicator about the file type. +.Bd -literal -offset 2n +#include <ftw.h> +#include <stdio.h> +#include <sysexits.h> + +int +nftw_callback(const char *path, const struct stat *sb, int typeflag, struct FTW *ftw) +{ + char type; + + switch(typeflag) { + case FTW_F: + type = 'F'; + break; + case FTW_D: + type = 'D'; + break; + case FTW_DNR: + type = '-'; + break; + case FTW_DP: + type = 'd'; + break; + case FTW_NS: + type = 'X'; + break; + case FTW_SL: + type = 'S'; + break; + case FTW_SLN: + type = 's'; + break; + default: + type = '?'; + break; + } + + printf("[%c] %s\\n", type, path); + + return (0); +} + +int +main(int argc, char **argv) +{ + + if (argc != 2) { + printf("Usage %s <directory>\\n", argv[0]); + return (EX_USAGE); + } else + return (nftw(argv[1], nftw_callback, /* UNUSED */ 1, 0)); +} +.Ed +.Sh ERRORS +The +.Fn ftw +and +.Fn nftw +functions may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr close 2 , +.Xr open 2 , +.Xr stat 2 , +.Xr malloc 3 , +.Xr opendir 3 +and +.Xr readdir 3 . +If the +.Dv FTW_CHDIR +flag is set, the +.Fn nftw +function may fail and set +.Va errno +for any of the errors specified for +.Xr chdir 2 . +In addition, either function may fail and set +.Va errno +as follows: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa maxfds +argument is less than 1. +.El +.Sh SEE ALSO +.Xr chdir 2 , +.Xr close 2 , +.Xr open 2 , +.Xr stat 2 , +.Xr fts 3 , +.Xr malloc 3 , +.Xr opendir 3 , +.Xr readdir 3 +.Sh STANDARDS +The +.Fn ftw +and +.Fn nftw +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +These functions first appeared in +.At V.3 . +Their first +.Fx +appearance was in +.Fx 5.3 . +.Sh BUGS +The +.Fa maxfds +argument is currently ignored. diff --git a/lib/libc/gen/ftw.c b/lib/libc/gen/ftw.c new file mode 100644 index 000000000000..35557d930bf4 --- /dev/null +++ b/lib/libc/gen/ftw.c @@ -0,0 +1,88 @@ +/* $OpenBSD: ftw.c,v 1.5 2005/08/08 08:05:34 espie Exp $ */ + +/* + * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fts.h> +#include <ftw.h> + +int +ftw(const char *path, int (*fn)(const char *, const struct stat *, int), + int nfds) +{ + char * const paths[2] = { (char *)path, NULL }; + FTSENT *cur; + FTS *ftsp; + int error = 0, fnflag, sverrno; + + /* XXX - nfds is currently unused */ + if (nfds < 1) { + errno = EINVAL; + return (-1); + } + + ftsp = fts_open(paths, FTS_LOGICAL | FTS_COMFOLLOW | FTS_NOCHDIR, NULL); + if (ftsp == NULL) + return (-1); + while ((cur = fts_read(ftsp)) != NULL) { + switch (cur->fts_info) { + case FTS_D: + fnflag = FTW_D; + break; + case FTS_DNR: + fnflag = FTW_DNR; + break; + case FTS_DP: + /* we only visit in preorder */ + continue; + case FTS_F: + case FTS_DEFAULT: + fnflag = FTW_F; + break; + case FTS_NS: + case FTS_NSOK: + case FTS_SLNONE: + fnflag = FTW_NS; + break; + case FTS_SL: + fnflag = FTW_SL; + break; + case FTS_DC: + errno = ELOOP; + /* FALLTHROUGH */ + default: + error = -1; + goto done; + } + error = fn(cur->fts_path, cur->fts_statp, fnflag); + if (error != 0) + break; + } +done: + sverrno = errno; + if (fts_close(ftsp) != 0 && error == 0) + error = -1; + else + errno = sverrno; + return (error); +} diff --git a/lib/libc/gen/gen-compat.h b/lib/libc/gen/gen-compat.h new file mode 100644 index 000000000000..19b9addb4321 --- /dev/null +++ b/lib/libc/gen/gen-compat.h @@ -0,0 +1,89 @@ +/*- + * Copyright (c) 2012 Gleb Kurtsou <gleb@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GEN_COMPAT_H_ +#define _GEN_COMPAT_H_ + +#include <dirent.h> + +#define FREEBSD11_DIRSIZ(dp) \ + (sizeof(struct freebsd11_dirent) - sizeof((dp)->d_name) + \ + (((dp)->d_namlen + 1 + 3) &~ 3)) + +struct freebsd11_dirent; +struct freebsd11_stat; +struct freebsd11_statfs; + +struct freebsd11_dirent *freebsd11_readdir(DIR *); +int freebsd11_readdir_r(DIR *, struct freebsd11_dirent *, + struct freebsd11_dirent **); + +int freebsd11_getmntinfo(struct freebsd11_statfs **, int); + +char *freebsd11_devname(__uint32_t dev, __mode_t type); +char *freebsd11_devname_r(__uint32_t dev, __mode_t type, char *buf, + int len); + +/* + * We want freebsd11_fstat in C source to result in resolution to + * - fstat@FBSD_1.0 for libc.so (but we do not need the _definition_ + * of this fstat, it is provided by libsys.so which we want to use). + * - freebsd11_fstat for libc.a (since if we make it fstat@FBSD_1.0 + * for libc.a, then final linkage into static object ignores version + * and would reference fstat, which is the current syscall, not the + * compat syscall). libc.a provides the freebsd11_fstat implementation. + * Note that freebsd11_fstat from libc.a is not used for anything, but + * we make it correct nonetheless, just in case it would. + * This is arranged by COMPAT_SYSCALL, and libc can just use freebsd11_fstat. + */ +#ifdef PIC +#define COMPAT_SYSCALL(rtype, fun, args, sym, ver) \ + rtype fun args; __sym_compat(sym, fun, ver); +#else +#define COMPAT_SYSCALL(rtype, fun, args, sym, ver) \ + rtype fun args; +#endif + +COMPAT_SYSCALL(int, freebsd11_stat, (const char *, struct freebsd11_stat *), + stat, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_lstat, (const char *, struct freebsd11_stat *), + lstat, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_fstat, (int, struct freebsd11_stat *), + fstat, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_fstatat, (int, const char *, + struct freebsd11_stat *, int), fstatat, FBSD_1.1); + +COMPAT_SYSCALL(int, freebsd11_statfs, (const char *, + struct freebsd11_statfs *), statfs, FBSD_1.0); +COMPAT_SYSCALL(int, freebsd11_getfsstat, (struct freebsd11_statfs *, long, + int), getfsstat, FBSD_1.0); + +COMPAT_SYSCALL(int, freebsd14_setgroups, (int gidsize, const __gid_t *gidset), + setgroups, FBSD_1.0); + +#undef COMPAT_SYSCALL + +#endif /* _GEN_COMPAT_H_ */ diff --git a/lib/libc/gen/gen-private.h b/lib/libc/gen/gen-private.h new file mode 100644 index 000000000000..b6749b3435cd --- /dev/null +++ b/lib/libc/gen/gen-private.h @@ -0,0 +1,66 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GEN_PRIVATE_H_ +#define _GEN_PRIVATE_H_ + +struct _telldir; /* see telldir.h */ +struct pthread_mutex; + +/* + * Structure describing an open directory. + * + * NOTE. Change structure layout with care, at least dd_fd field has to + * remain unchanged to guarantee backward compatibility. + */ +struct _dirdesc { + int dd_fd; /* file descriptor associated with directory */ + size_t dd_loc; /* offset in current buffer */ + size_t dd_size; /* amount of data returned by getdirentries */ + char *dd_buf; /* data buffer */ + int dd_len; /* size of data buffer */ + off_t dd_seek; /* magic cookie returned by getdirentries */ + int dd_flags; /* flags for readdir */ +#ifndef IN_RTLD + struct pthread_mutex *dd_lock; /* lock */ +#else + struct _donotuse *dd_lock; /* unused in rtld, keep same layout */ +#endif + struct _telldir *dd_td; /* telldir position recording */ + void *dd_compat_de; /* compat dirent */ +}; + +#define _dirfd(dirp) ((dirp)->dd_fd) + +struct dirent; +int __readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result); + +#endif /* !_GEN_PRIVATE_H_ */ diff --git a/lib/libc/gen/getbootfile.3 b/lib/libc/gen/getbootfile.3 new file mode 100644 index 000000000000..a857b3e8859e --- /dev/null +++ b/lib/libc/gen/getbootfile.3 @@ -0,0 +1,66 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd September 23, 1994 +.Dt GETBOOTFILE 3 +.Os +.Sh NAME +.Nm getbootfile +.Nd get kernel boot file name +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In paths.h +.Ft const char * +.Fn getbootfile void +.Sh DESCRIPTION +The +.Fn getbootfile +function retrieves the full pathname of the file from which the +current kernel was loaded, and returns a static pointer to the name. +A read/write interface to this information is available via the +.Xr sysctl 3 +MIB variable +.Dq Li kern.bootfile . +.Sh RETURN VALUES +If the call succeeds a string giving the pathname is returned. +If it +fails, a null pointer is returned and an error code is +placed in the global location +.Va errno . +.Sh SEE ALSO +.Xr sysctl 3 +.Sh HISTORY +The +.Fn getbootfile +function appeared in +.Fx 2.0 . +.Sh BUGS +If the boot blocks have not been modified to pass this information into +the kernel at boot time, the static string +.Dq Pa /boot/kernel/kernel +is returned instead of the real boot file. diff --git a/lib/libc/gen/getbootfile.c b/lib/libc/gen/getbootfile.c new file mode 100644 index 000000000000..6250e3e2509b --- /dev/null +++ b/lib/libc/gen/getbootfile.c @@ -0,0 +1,49 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <paths.h> + +const char * +getbootfile(void) +{ + static char name[MAXPATHLEN]; + size_t size = sizeof name; + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTFILE; + if (sysctl(mib, 2, name, &size, NULL, 0) == -1) + return ("/boot/kernel/kernel"); + return (name); +} diff --git a/lib/libc/gen/getbsize.3 b/lib/libc/gen/getbsize.3 new file mode 100644 index 000000000000..1d9d43fdfffb --- /dev/null +++ b/lib/libc/gen/getbsize.3 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 11, 2017 +.Dt GETBSIZE 3 +.Os +.Sh NAME +.Nm getbsize +.Nd get preferred block size +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft char * +.Fn getbsize "int *headerlenp" "long *blocksizep" +.Sh DESCRIPTION +The +.Fn getbsize +function returns a preferred block size for reporting by system utilities +.Xr df 1 , +.Xr du 1 +and +.Xr ls 1 , +based on the value of the +.Ev BLOCKSIZE +environment variable. +.Ev BLOCKSIZE +may be specified directly in bytes, or in multiples of a kilobyte by +specifying a number followed by ``K'' or ``k'', in multiples of a +megabyte by specifying a number followed by ``M'' or ``m'' or in +multiples of a gigabyte by specifying a number followed by ``G'' or +``g''. +Multiples must be integers. +.Pp +Valid values of +.Ev BLOCKSIZE +are 512 bytes to 1 gigabyte. +Sizes less than 512 bytes are rounded up to 512 bytes, and sizes +greater than 1 GB are rounded down to 1 GB. +In each case +.Fn getbsize +produces a warning message via +.Xr warnx 3 . +.Pp +The +.Fn getbsize +function returns a pointer to a null-terminated string describing +the block size, something like +.Dq 1K-blocks . +The memory referenced by +.Fa headerlenp +is filled in with the length of the string (not including the +terminating null). +The memory referenced by +.Fa blocksizep +is filled in with block size, in bytes. +.Sh SEE ALSO +.Xr df 1 , +.Xr du 1 , +.Xr ls 1 , +.Xr systat 1 , +.Xr environ 7 +.Sh HISTORY +The +.Fn getbsize +function first appeared in +.Bx 4.4 . diff --git a/lib/libc/gen/getbsize.c b/lib/libc/gen/getbsize.c new file mode 100644 index 000000000000..efcabea663a0 --- /dev/null +++ b/lib/libc/gen/getbsize.c @@ -0,0 +1,100 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <err.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +char * +getbsize(int *headerlenp, long *blocksizep) +{ + static char header[20]; + long n, max, mul, blocksize; + char *ep, *p; + const char *form; + +#define KB (1024L) +#define MB (1024L * 1024L) +#define GB (1024L * 1024L * 1024L) +#define MAXB GB /* No tera, peta, nor exa. */ + form = ""; + if ((p = getenv("BLOCKSIZE")) != NULL && *p != '\0') { + if ((n = strtol(p, &ep, 10)) < 0) + goto underflow; + if (n == 0) + n = 1; + if (*ep && ep[1]) + goto fmterr; + switch (*ep) { + case 'G': case 'g': + form = "G"; + max = MAXB / GB; + mul = GB; + break; + case 'K': case 'k': + form = "K"; + max = MAXB / KB; + mul = KB; + break; + case 'M': case 'm': + form = "M"; + max = MAXB / MB; + mul = MB; + break; + case '\0': + max = MAXB; + mul = 1; + break; + default: +fmterr: warnx("%s: unknown blocksize", p); + n = 512; + max = MAXB; + mul = 1; + break; + } + if (n > max) { + warnx("maximum blocksize is %ldG", MAXB / GB); + n = max; + } + if ((blocksize = n * mul) < 512) { +underflow: warnx("minimum blocksize is 512"); + form = ""; + blocksize = n = 512; + } + } else + blocksize = n = 512; + + (void)snprintf(header, sizeof(header), "%ld%s-blocks", n, form); + *headerlenp = strlen(header); + *blocksizep = blocksize; + return (header); +} diff --git a/lib/libc/gen/getcap.3 b/lib/libc/gen/getcap.3 new file mode 100644 index 000000000000..00c7edd8026f --- /dev/null +++ b/lib/libc/gen/getcap.3 @@ -0,0 +1,566 @@ +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Casey Leedom of Lawrence Livermore National Laboratory. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd March 22, 2002 +.Dt GETCAP 3 +.Os +.Sh NAME +.Nm cgetent , +.Nm cgetset , +.Nm cgetmatch , +.Nm cgetcap , +.Nm cgetnum , +.Nm cgetstr , +.Nm cgetustr , +.Nm cgetfirst , +.Nm cgetnext , +.Nm cgetclose +.Nd capability database access routines +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn cgetent "char **buf" "char **db_array" "const char *name" +.Ft int +.Fn cgetset "const char *ent" +.Ft int +.Fn cgetmatch "const char *buf" "const char *name" +.Ft char * +.Fn cgetcap "char *buf" "const char *cap" "int type" +.Ft int +.Fn cgetnum "char *buf" "const char *cap" "long *num" +.Ft int +.Fn cgetstr "char *buf" "const char *cap" "char **str" +.Ft int +.Fn cgetustr "char *buf" "const char *cap" "char **str" +.Ft int +.Fn cgetfirst "char **buf" "char **db_array" +.Ft int +.Fn cgetnext "char **buf" "char **db_array" +.Ft int +.Fn cgetclose "void" +.Sh DESCRIPTION +The +.Fn cgetent +function extracts the capability +.Fa name +from the database specified by the +.Dv NULL +terminated file array +.Fa db_array +and returns a pointer to a +.Xr malloc 3 Ns \&'d +copy of it in +.Fa buf . +The +.Fn cgetent +function will first look for files ending in +.Pa .db +(see +.Xr cap_mkdb 1 ) +before accessing the ASCII file. +The +.Fa buf +argument +must be retained through all subsequent calls to +.Fn cgetmatch , +.Fn cgetcap , +.Fn cgetnum , +.Fn cgetstr , +and +.Fn cgetustr , +but may then be +.Xr free 3 Ns \&'d . +On success 0 is returned, 1 if the returned +record contains an unresolved +.Ic tc +expansion, +\-1 if the requested record could not be found, +\-2 if a system error was encountered (could not open/read a file, etc.) also +setting +.Va errno , +and \-3 if a potential reference loop is detected (see +.Ic tc= +comments below). +.Pp +The +.Fn cgetset +function enables the addition of a character buffer containing a single capability +record entry +to the capability database. +Conceptually, the entry is added as the first ``file'' in the database, and +is therefore searched first on the call to +.Fn cgetent . +The entry is passed in +.Fa ent . +If +.Fa ent +is +.Dv NULL , +the current entry is removed from the database. +A call to +.Fn cgetset +must precede the database traversal. +It must be called before the +.Fn cgetent +call. +If a sequential access is being performed (see below), it must be called +before the first sequential access call +.Po Fn cgetfirst +or +.Fn cgetnext +.Pc , +or be directly preceded by a +.Fn cgetclose +call. +On success 0 is returned and \-1 on failure. +.Pp +The +.Fn cgetmatch +function will return 0 if +.Fa name +is one of the names of the capability record +.Fa buf , +\-1 if +not. +.Pp +The +.Fn cgetcap +function searches the capability record +.Fa buf +for the capability +.Fa cap +with type +.Fa type . +A +.Fa type +is specified using any single character. +If a colon (`:') is used, an +untyped capability will be searched for (see below for explanation of +types). +A pointer to the value of +.Fa cap +in +.Fa buf +is returned on success, +.Dv NULL +if the requested capability could not be +found. +The end of the capability value is signaled by a `:' or +.Tn ASCII +.Dv NUL +(see below for capability database syntax). +.Pp +The +.Fn cgetnum +function retrieves the value of the numeric capability +.Fa cap +from the capability record pointed to by +.Fa buf . +The numeric value is returned in the +.Ft long +pointed to by +.Fa num . +0 is returned on success, \-1 if the requested numeric capability could not +be found. +.Pp +The +.Fn cgetstr +function retrieves the value of the string capability +.Fa cap +from the capability record pointed to by +.Fa buf . +A pointer to a decoded, +.Dv NUL +terminated, +.Xr malloc 3 Ns \&'d +copy of the string is returned in the +.Ft char * +pointed to by +.Fa str . +The number of characters in the decoded string not including the trailing +.Dv NUL +is returned on success, \-1 if the requested string capability could not +be found, \-2 if a system error was encountered (storage allocation +failure). +.Pp +The +.Fn cgetustr +function is identical to +.Fn cgetstr +except that it does not expand special characters, but rather returns each +character of the capability string literally. +.Pp +The +.Fn cgetfirst +and +.Fn cgetnext +functions comprise a function group that provides for sequential +access of the +.Dv NULL +pointer terminated array of file names, +.Fa db_array . +The +.Fn cgetfirst +function returns the first record in the database and resets the access +to the first record. +The +.Fn cgetnext +function returns the next record in the database with respect to the +record returned by the previous +.Fn cgetfirst +or +.Fn cgetnext +call. +If there is no such previous call, the first record in the database is +returned. +Each record is returned in a +.Xr malloc 3 Ns \&'d +copy pointed to by +.Fa buf . +.Ic Tc +expansion is done (see +.Ic tc= +comments below). +Upon completion of the database 0 is returned, 1 is returned upon successful +return of record with possibly more remaining (we have not reached the end of +the database yet), 2 is returned if the record contains an unresolved +.Ic tc +expansion, \-1 is returned if a system error occurred, and \-2 +is returned if a potential reference loop is detected (see +.Ic tc= +comments below). +Upon completion of database (0 return) the database is closed. +.Pp +The +.Fn cgetclose +function closes the sequential access and frees any memory and file descriptors +being used. +Note that it does not erase the buffer pushed by a call to +.Fn cgetset . +.Sh CAPABILITY DATABASE SYNTAX +Capability databases are normally +.Tn ASCII +and may be edited with standard +text editors. +Blank lines and lines beginning with a `#' are comments +and are ignored. +Lines ending with a `\|\e' indicate that the next line +is a continuation of the current line; the `\|\e' and following newline +are ignored. +Long lines are usually continued onto several physical +lines by ending each line except the last with a `\|\e'. +.Pp +Capability databases consist of a series of records, one per logical +line. +Each record contains a variable number of `:'-separated fields +(capabilities). +Empty fields consisting entirely of white space +characters (spaces and tabs) are ignored. +.Pp +The first capability of each record specifies its names, separated by `|' +characters. +These names are used to reference records in the database. +By convention, the last name is usually a comment and is not intended as +a lookup tag. +For example, the +.Em vt100 +record from the +.Xr termcap 5 +database begins: +.Pp +.Dl "d0\||\|vt100\||\|vt100-am\||\|vt100am\||\|dec vt100:" +.Pp +giving four names that can be used to access the record. +.Pp +The remaining non-empty capabilities describe a set of (name, value) +bindings, consisting of a names optionally followed by a typed value: +.Pp +.Bl -tag -width "nameTvalue" -compact +.It name +typeless [boolean] capability +.Em name No "is present [true]" +.It name Ns Em \&T Ns value +capability +.Pq Em name , \&T +has value +.Em value +.It name@ +no capability +.Em name No exists +.It name Ns Em T Ns \&@ +capability +.Pq Em name , T +does not exist +.El +.Pp +Names consist of one or more characters. +Names may contain any character +except `:', but it is usually best to restrict them to the printable +characters and avoid use of graphics like `#', `=', `%', `@', etc. +Types +are single characters used to separate capability names from their +associated typed values. +Types may be any character except a `:'. +Typically, graphics like `#', `=', `%', etc.\& are used. +Values may be any +number of characters and may contain any character except `:'. +.Sh CAPABILITY DATABASE SEMANTICS +Capability records describe a set of (name, value) bindings. +Names may +have multiple values bound to them. +Different values for a name are +distinguished by their +.Fa types . +The +.Fn cgetcap +function will return a pointer to a value of a name given the capability +name and the type of the value. +.Pp +The types `#' and `=' are conventionally used to denote numeric and +string typed values, but no restriction on those types is enforced. +The +functions +.Fn cgetnum +and +.Fn cgetstr +can be used to implement the traditional syntax and semantics of `#' +and `='. +Typeless capabilities are typically used to denote boolean objects with +presence or absence indicating truth and false values respectively. +This interpretation is conveniently represented by: +.Pp +.Dl "(getcap(buf, name, ':') != NULL)" +.Pp +A special capability, +.Ic tc= name , +is used to indicate that the record specified by +.Fa name +should be substituted for the +.Ic tc +capability. +.Ic Tc +capabilities may interpolate records which also contain +.Ic tc +capabilities and more than one +.Ic tc +capability may be used in a record. +A +.Ic tc +expansion scope (i.e., where the argument is searched for) contains the +file in which the +.Ic tc +is declared and all subsequent files in the file array. +.Pp +When a database is searched for a capability record, the first matching +record in the search is returned. +When a record is scanned for a +capability, the first matching capability is returned; the capability +.Ic :nameT@: +will hide any following definition of a value of type +.Em T +for +.Fa name ; +and the capability +.Ic :name@: +will prevent any following values of +.Fa name +from being seen. +.Pp +These features combined with +.Ic tc +capabilities can be used to generate variations of other databases and +records by either adding new capabilities, overriding definitions with new +definitions, or hiding following definitions via `@' capabilities. +.Sh EXAMPLES +.Bd -unfilled -offset indent +example\||\|an example of binding multiple values to names:\e + :foo%bar:foo^blah:foo@:\e + :abc%xyz:abc^frap:abc$@:\e + :tc=more: +.Ed +.Pp +The capability foo has two values bound to it (bar of type `%' and blah of +type `^') and any other value bindings are hidden. +The capability abc +also has two values bound but only a value of type `$' is prevented from +being defined in the capability record more. +.Bd -unfilled -offset indent +file1: + new\||\|new_record\||\|a modification of "old":\e + :fript=bar:who-cares@:tc=old:blah:tc=extensions: +file2: + old\||\|old_record\||\|an old database record:\e + :fript=foo:who-cares:glork#200: +.Ed +.Pp +The records are extracted by calling +.Fn cgetent +with file1 preceding file2. +In the capability record new in file1, fript=bar overrides the definition +of fript=foo interpolated from the capability record old in file2, +who-cares@ prevents the definition of any who-cares definitions in old +from being seen, glork#200 is inherited from old, and blah and anything +defined by the record extensions is added to those definitions in old. +Note that the position of the fript=bar and who-cares@ definitions before +tc=old is important here. +If they were after, the definitions in old +would take precedence. +.Sh CGETNUM AND CGETSTR SYNTAX AND SEMANTICS +Two types are predefined by +.Fn cgetnum +and +.Fn cgetstr : +.Pp +.Bl -tag -width "nameXnumber" -compact +.It Em name Ns \&# Ns Em number +numeric capability +.Em name +has value +.Em number +.It Em name Ns = Ns Em string +string capability +.Em name +has value +.Em string +.It Em name Ns \&#@ +the numeric capability +.Em name +does not exist +.It Em name Ns \&=@ +the string capability +.Em name +does not exist +.El +.Pp +Numeric capability values may be given in one of three numeric bases. +If the number starts with either +.Ql 0x +or +.Ql 0X +it is interpreted as a hexadecimal number (both upper and lower case a-f +may be used to denote the extended hexadecimal digits). +Otherwise, if the number starts with a +.Ql 0 +it is interpreted as an octal number. +Otherwise the number is interpreted as a decimal number. +.Pp +String capability values may contain any character. +Non-printable +.Dv ASCII +codes, new lines, and colons may be conveniently represented by the use +of escape sequences: +.Bl -column "\e\|X,X\e\|X" "(ASCII octal nnn)" +^X ('X' & 037) control-X +\e\|b, \e\|B (ASCII 010) backspace +\e\|t, \e\|T (ASCII 011) tab +\e\|n, \e\|N (ASCII 012) line feed (newline) +\e\|f, \e\|F (ASCII 014) form feed +\e\|r, \e\|R (ASCII 015) carriage return +\e\|e, \e\|E (ASCII 027) escape +\e\|c, \e\|C (:) colon +\e\|\e (\e\|) back slash +\e\|^ (^) caret +\e\|nnn (ASCII octal nnn) +.El +.Pp +A `\|\e' may be followed by up to three octal digits directly specifies +the numeric code for a character. +The use of +.Tn ASCII +.Dv NUL Ns s , +while easily +encoded, causes all sorts of problems and must be used with care since +.Dv NUL Ns s +are typically used to denote the end of strings; many applications +use `\e\|200' to represent a +.Dv NUL . +.Sh DIAGNOSTICS +The +.Fn cgetent , +.Fn cgetset , +.Fn cgetmatch , +.Fn cgetnum , +.Fn cgetstr , +.Fn cgetustr , +.Fn cgetfirst , +and +.Fn cgetnext +functions +return a value greater than or equal to 0 on success and a value less +than 0 on failure. +The +.Fn cgetcap +function returns a character pointer on success and a +.Dv NULL +on failure. +.Pp +The +.Fn cgetent , +and +.Fn cgetset +functions may fail and set +.Va errno +for any of the errors specified for the library functions: +.Xr fopen 3 , +.Xr fclose 3 , +.Xr open 2 , +and +.Xr close 2 . +.Pp +The +.Fn cgetent , +.Fn cgetset , +.Fn cgetstr , +and +.Fn cgetustr +functions +may fail and set +.Va errno +as follows: +.Bl -tag -width Er +.It Bq Er ENOMEM +No memory to allocate. +.El +.Sh SEE ALSO +.Xr cap_mkdb 1 , +.Xr malloc 3 +.Sh BUGS +Colons (`:') cannot be used in names, types, or values. +.Pp +There are no checks for +.Ic tc Ns = Ns Ic name +loops in +.Fn cgetent . +.Pp +The buffer added to the database by a call to +.Fn cgetset +is not unique to the database but is rather prepended to any database used. diff --git a/lib/libc/gen/getcap.c b/lib/libc/gen/getcap.c new file mode 100644 index 000000000000..cfb81ed0d065 --- /dev/null +++ b/lib/libc/gen/getcap.c @@ -0,0 +1,1051 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Casey Leedom of Lawrence Livermore National Laboratory. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> + +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include <db.h> + +#define BFRAG 1024 +#define BSIZE 1024 +#define ESC ('[' & 037) /* ASCII ESC */ +#define MAX_RECURSION 32 /* maximum getent recursion */ +#define SFRAG 100 /* cgetstr mallocs in SFRAG chunks */ + +#define RECOK (char)0 +#define TCERR (char)1 +#define SHADOW (char)2 + +static size_t topreclen; /* toprec length */ +static char *toprec; /* Additional record specified by cgetset() */ +static int gottoprec; /* Flag indicating retrieval of toprecord */ + +static int cdbget(DB *, char **, const char *); +static int getent(char **, u_int *, char **, int, const char *, int, char *); +static int nfcmp(char *, char *); + +/* + * Cgetset() allows the addition of a user specified buffer to be added + * to the database array, in effect "pushing" the buffer on top of the + * virtual database. 0 is returned on success, -1 on failure. + */ +int +cgetset(const char *ent) +{ + if (ent == NULL) { + if (toprec) + free(toprec); + toprec = NULL; + topreclen = 0; + return (0); + } + topreclen = strlen(ent); + if ((toprec = malloc (topreclen + 1)) == NULL) { + errno = ENOMEM; + return (-1); + } + gottoprec = 0; + (void)strcpy(toprec, ent); + return (0); +} + +/* + * Cgetcap searches the capability record buf for the capability cap with + * type `type'. A pointer to the value of cap is returned on success, NULL + * if the requested capability couldn't be found. + * + * Specifying a type of ':' means that nothing should follow cap (:cap:). + * In this case a pointer to the terminating ':' or NUL will be returned if + * cap is found. + * + * If (cap, '@') or (cap, terminator, '@') is found before (cap, terminator) + * return NULL. + */ +char * +cgetcap(char *buf, const char *cap, int type) +{ + char *bp; + const char *cp; + + bp = buf; + for (;;) { + /* + * Skip past the current capability field - it's either the + * name field if this is the first time through the loop, or + * the remainder of a field whose name failed to match cap. + */ + for (;;) + if (*bp == '\0') + return (NULL); + else + if (*bp++ == ':') + break; + + /* + * Try to match (cap, type) in buf. + */ + for (cp = cap; *cp == *bp && *bp != '\0'; cp++, bp++) + continue; + if (*cp != '\0') + continue; + if (*bp == '@') + return (NULL); + if (type == ':') { + if (*bp != '\0' && *bp != ':') + continue; + return(bp); + } + if (*bp != type) + continue; + bp++; + return (*bp == '@' ? NULL : bp); + } + /* NOTREACHED */ +} + +/* + * Cgetent extracts the capability record name from the NULL terminated file + * array db_array and returns a pointer to a malloc'd copy of it in buf. + * Buf must be retained through all subsequent calls to cgetcap, cgetnum, + * cgetflag, and cgetstr, but may then be free'd. 0 is returned on success, + * -1 if the requested record couldn't be found, -2 if a system error was + * encountered (couldn't open/read a file, etc.), and -3 if a potential + * reference loop is detected. + */ +int +cgetent(char **buf, char **db_array, const char *name) +{ + u_int dummy; + + return (getent(buf, &dummy, db_array, -1, name, 0, NULL)); +} + +/* + * Getent implements the functions of cgetent. If fd is non-negative, + * *db_array has already been opened and fd is the open file descriptor. We + * do this to save time and avoid using up file descriptors for tc= + * recursions. + * + * Getent returns the same success/failure codes as cgetent. On success, a + * pointer to a malloc'ed capability record with all tc= capabilities fully + * expanded and its length (not including trailing ASCII NUL) are left in + * *cap and *len. + * + * Basic algorithm: + * + Allocate memory incrementally as needed in chunks of size BFRAG + * for capability buffer. + * + Recurse for each tc=name and interpolate result. Stop when all + * names interpolated, a name can't be found, or depth exceeds + * MAX_RECURSION. + */ +static int +getent(char **cap, u_int *len, char **db_array, int fd, const char *name, + int depth, char *nfield) +{ + DB *capdbp; + char *r_end, *rp, **db_p; + int myfd, eof, foundit, retval; + char *record, *cbuf; + int tc_not_resolved; + char pbuf[_POSIX_PATH_MAX]; + + /* + * Return with ``loop detected'' error if we've recursed more than + * MAX_RECURSION times. + */ + if (depth > MAX_RECURSION) + return (-3); + + /* + * Check if we have a top record from cgetset(). + */ + if (depth == 0 && toprec != NULL && cgetmatch(toprec, name) == 0) { + if ((record = malloc (topreclen + BFRAG)) == NULL) { + errno = ENOMEM; + return (-2); + } + (void)strcpy(record, toprec); + myfd = 0; + db_p = db_array; + rp = record + topreclen + 1; + r_end = rp + BFRAG; + goto tc_exp; + } + /* + * Allocate first chunk of memory. + */ + if ((record = malloc(BFRAG)) == NULL) { + errno = ENOMEM; + return (-2); + } + r_end = record + BFRAG; + foundit = 0; + /* + * Loop through database array until finding the record. + */ + + for (db_p = db_array; *db_p != NULL; db_p++) { + eof = 0; + + /* + * Open database if not already open. + */ + + if (fd >= 0) { + (void)lseek(fd, (off_t)0, SEEK_SET); + myfd = 0; + } else { + (void)snprintf(pbuf, sizeof(pbuf), "%s.db", *db_p); + if ((capdbp = dbopen(pbuf, O_RDONLY, 0, DB_HASH, 0)) + != NULL) { + free(record); + retval = cdbget(capdbp, &record, name); + if (retval < 0) { + /* no record available */ + (void)capdbp->close(capdbp); + return (retval); + } + /* save the data; close frees it */ + cbuf = strdup(record); + if (capdbp->close(capdbp) < 0) { + free(cbuf); + return (-2); + } + if (cbuf == NULL) { + errno = ENOMEM; + return (-2); + } + *len = strlen(cbuf); + *cap = cbuf; + return (retval); + } else { + fd = _open(*db_p, O_RDONLY | O_CLOEXEC, 0); + if (fd < 0) + continue; + myfd = 1; + } + } + /* + * Find the requested capability record ... + */ + { + char buf[BUFSIZ]; + char *b_end, *bp; + int c; + + /* + * Loop invariants: + * There is always room for one more character in record. + * R_end always points just past end of record. + * Rp always points just past last character in record. + * B_end always points just past last character in buf. + * Bp always points at next character in buf. + */ + b_end = buf; + bp = buf; + for (;;) { + + /* + * Read in a line implementing (\, newline) + * line continuation. + */ + rp = record; + for (;;) { + if (bp >= b_end) { + int n; + + n = _read(fd, buf, sizeof(buf)); + if (n <= 0) { + if (myfd) + (void)_close(fd); + if (n < 0) { + free(record); + return (-2); + } else { + fd = -1; + eof = 1; + break; + } + } + b_end = buf+n; + bp = buf; + } + + c = *bp++; + if (c == '\n') { + if (rp > record && *(rp-1) == '\\') { + rp--; + continue; + } else + break; + } + *rp++ = c; + + /* + * Enforce loop invariant: if no room + * left in record buffer, try to get + * some more. + */ + if (rp >= r_end) { + u_int pos; + size_t newsize; + + pos = rp - record; + newsize = r_end - record + BFRAG; + record = reallocf(record, newsize); + if (record == NULL) { + errno = ENOMEM; + if (myfd) + (void)_close(fd); + return (-2); + } + r_end = record + newsize; + rp = record + pos; + } + } + /* loop invariant let's us do this */ + *rp++ = '\0'; + + /* + * If encountered eof check next file. + */ + if (eof) + break; + + /* + * Toss blank lines and comments. + */ + if (*record == '\0' || *record == '#') + continue; + + /* + * See if this is the record we want ... + */ + if (cgetmatch(record, name) == 0) { + if (nfield == NULL || !nfcmp(nfield, record)) { + foundit = 1; + break; /* found it! */ + } + } + } + } + if (foundit) + break; + } + + if (!foundit) { + free(record); + return (-1); + } + + /* + * Got the capability record, but now we have to expand all tc=name + * references in it ... + */ +tc_exp: { + char *newicap, *s; + int newilen; + u_int ilen; + int diff, iret, tclen; + char *icap, *scan, *tc, *tcstart, *tcend; + + /* + * Loop invariants: + * There is room for one more character in record. + * R_end points just past end of record. + * Rp points just past last character in record. + * Scan points at remainder of record that needs to be + * scanned for tc=name constructs. + */ + scan = record; + tc_not_resolved = 0; + for (;;) { + if ((tc = cgetcap(scan, "tc", '=')) == NULL) + break; + + /* + * Find end of tc=name and stomp on the trailing `:' + * (if present) so we can use it to call ourselves. + */ + s = tc; + for (;;) + if (*s == '\0') + break; + else + if (*s++ == ':') { + *(s - 1) = '\0'; + break; + } + tcstart = tc - 3; + tclen = s - tcstart; + tcend = s; + + iret = getent(&icap, &ilen, db_p, fd, tc, depth+1, + NULL); + newicap = icap; /* Put into a register. */ + newilen = ilen; + if (iret != 0) { + /* an error */ + if (iret < -1) { + if (myfd) + (void)_close(fd); + free(record); + return (iret); + } + if (iret == 1) + tc_not_resolved = 1; + /* couldn't resolve tc */ + if (iret == -1) { + *(s - 1) = ':'; + scan = s - 1; + tc_not_resolved = 1; + continue; + + } + } + /* not interested in name field of tc'ed record */ + s = newicap; + for (;;) + if (*s == '\0') + break; + else + if (*s++ == ':') + break; + newilen -= s - newicap; + newicap = s; + + /* make sure interpolated record is `:'-terminated */ + s += newilen; + if (*(s-1) != ':') { + *s = ':'; /* overwrite NUL with : */ + newilen++; + } + + /* + * Make sure there's enough room to insert the + * new record. + */ + diff = newilen - tclen; + if (diff >= r_end - rp) { + u_int pos, tcpos, tcposend; + size_t newsize; + + pos = rp - record; + newsize = r_end - record + diff + BFRAG; + tcpos = tcstart - record; + tcposend = tcend - record; + record = reallocf(record, newsize); + if (record == NULL) { + errno = ENOMEM; + if (myfd) + (void)_close(fd); + free(icap); + return (-2); + } + r_end = record + newsize; + rp = record + pos; + tcstart = record + tcpos; + tcend = record + tcposend; + } + + /* + * Insert tc'ed record into our record. + */ + s = tcstart + newilen; + bcopy(tcend, s, rp - tcend); + bcopy(newicap, tcstart, newilen); + rp += diff; + free(icap); + + /* + * Start scan on `:' so next cgetcap works properly + * (cgetcap always skips first field). + */ + scan = s-1; + } + + } + /* + * Close file (if we opened it), give back any extra memory, and + * return capability, length and success. + */ + if (myfd) + (void)_close(fd); + *len = rp - record - 1; /* don't count NUL */ + if (r_end > rp) + if ((record = + reallocf(record, (size_t)(rp - record))) == NULL) { + errno = ENOMEM; + return (-2); + } + + *cap = record; + if (tc_not_resolved) + return (1); + return (0); +} + +static int +cdbget(DB *capdbp, char **bp, const char *name) +{ + DBT key, data; + char *namebuf; + + namebuf = strdup(name); + if (namebuf == NULL) + return (-2); + key.data = namebuf; + key.size = strlen(namebuf); + + for (;;) { + /* Get the reference. */ + switch(capdbp->get(capdbp, &key, &data, 0)) { + case -1: + free(namebuf); + return (-2); + case 1: + free(namebuf); + return (-1); + } + + /* If not an index to another record, leave. */ + if (((char *)data.data)[0] != SHADOW) + break; + + key.data = (char *)data.data + 1; + key.size = data.size - 1; + } + + *bp = (char *)data.data + 1; + free(namebuf); + return (((char *)(data.data))[0] == TCERR ? 1 : 0); +} + +/* + * Cgetmatch will return 0 if name is one of the names of the capability + * record buf, -1 if not. + */ +int +cgetmatch(const char *buf, const char *name) +{ + const char *np, *bp; + + if (name == NULL || *name == '\0') + return -1; + + /* + * Start search at beginning of record. + */ + bp = buf; + for (;;) { + /* + * Try to match a record name. + */ + np = name; + for (;;) + if (*np == '\0') + if (*bp == '|' || *bp == ':' || *bp == '\0') + return (0); + else + break; + else + if (*bp++ != *np++) + break; + + /* + * Match failed, skip to next name in record. + */ + bp--; /* a '|' or ':' may have stopped the match */ + for (;;) + if (*bp == '\0' || *bp == ':') + return (-1); /* match failed totally */ + else + if (*bp++ == '|') + break; /* found next name */ + } +} + + + + + +int +cgetfirst(char **buf, char **db_array) +{ + (void)cgetclose(); + return (cgetnext(buf, db_array)); +} + +static FILE *pfp; +static int slash; +static char **dbp; + +int +cgetclose(void) +{ + if (pfp != NULL) { + (void)fclose(pfp); + pfp = NULL; + } + dbp = NULL; + gottoprec = 0; + slash = 0; + return(0); +} + +/* + * Cgetnext() gets either the first or next entry in the logical database + * specified by db_array. It returns 0 upon completion of the database, 1 + * upon returning an entry with more remaining, and -1 if an error occurs. + */ +int +cgetnext(char **bp, char **db_array) +{ + size_t len; + int done, hadreaderr, savederrno, status; + char *cp, *line, *rp, *np, buf[BSIZE], nbuf[BSIZE]; + u_int dummy; + + if (dbp == NULL) + dbp = db_array; + + if (pfp == NULL && (pfp = fopen(*dbp, "re")) == NULL) { + (void)cgetclose(); + return (-1); + } + for (;;) { + if (toprec && !gottoprec) { + gottoprec = 1; + line = toprec; + } else { + line = fgetln(pfp, &len); + if (line == NULL && pfp) { + hadreaderr = ferror(pfp); + if (hadreaderr) + savederrno = errno; + fclose(pfp); + pfp = NULL; + if (hadreaderr) { + cgetclose(); + errno = savederrno; + return (-1); + } else { + if (*++dbp == NULL) { + (void)cgetclose(); + return (0); + } else if ((pfp = + fopen(*dbp, "re")) == NULL) { + (void)cgetclose(); + return (-1); + } else + continue; + } + } else + line[len - 1] = '\0'; + if (len == 1) { + slash = 0; + continue; + } + if (isspace((unsigned char)*line) || + *line == ':' || *line == '#' || slash) { + if (line[len - 2] == '\\') + slash = 1; + else + slash = 0; + continue; + } + if (line[len - 2] == '\\') + slash = 1; + else + slash = 0; + } + + + /* + * Line points to a name line. + */ + done = 0; + np = nbuf; + for (;;) { + for (cp = line; *cp != '\0'; cp++) { + if (*cp == ':') { + *np++ = ':'; + done = 1; + break; + } + if (*cp == '\\') + break; + *np++ = *cp; + } + if (done) { + *np = '\0'; + break; + } else { /* name field extends beyond the line */ + line = fgetln(pfp, &len); + if (line == NULL && pfp) { + /* Name extends beyond the EOF! */ + hadreaderr = ferror(pfp); + if (hadreaderr) + savederrno = errno; + fclose(pfp); + pfp = NULL; + if (hadreaderr) { + cgetclose(); + errno = savederrno; + return (-1); + } else { + cgetclose(); + return (-1); + } + } else + line[len - 1] = '\0'; + } + } + rp = buf; + for(cp = nbuf; *cp != '\0'; cp++) + if (*cp == '|' || *cp == ':') + break; + else + *rp++ = *cp; + + *rp = '\0'; + /* + * XXX + * Last argument of getent here should be nbuf if we want true + * sequential access in the case of duplicates. + * With NULL, getent will return the first entry found + * rather than the duplicate entry record. This is a + * matter of semantics that should be resolved. + */ + status = getent(bp, &dummy, db_array, -1, buf, 0, NULL); + if (status == -2 || status == -3) + (void)cgetclose(); + + return (status + 1); + } + /* NOTREACHED */ +} + +/* + * Cgetstr retrieves the value of the string capability cap from the + * capability record pointed to by buf. A pointer to a decoded, NUL + * terminated, malloc'd copy of the string is returned in the char * + * pointed to by str. The length of the string not including the trailing + * NUL is returned on success, -1 if the requested string capability + * couldn't be found, -2 if a system error was encountered (storage + * allocation failure). + */ +int +cgetstr(char *buf, const char *cap, char **str) +{ + u_int m_room; + char *bp, *mp; + int len; + char *mem; + + /* + * Find string capability cap + */ + bp = cgetcap(buf, cap, '='); + if (bp == NULL) + return (-1); + + /* + * Conversion / storage allocation loop ... Allocate memory in + * chunks SFRAG in size. + */ + if ((mem = malloc(SFRAG)) == NULL) { + errno = ENOMEM; + return (-2); /* couldn't even allocate the first fragment */ + } + m_room = SFRAG; + mp = mem; + + while (*bp != ':' && *bp != '\0') { + /* + * Loop invariants: + * There is always room for one more character in mem. + * Mp always points just past last character in mem. + * Bp always points at next character in buf. + */ + if (*bp == '^') { + bp++; + if (*bp == ':' || *bp == '\0') + break; /* drop unfinished escape */ + if (*bp == '?') { + *mp++ = '\177'; + bp++; + } else + *mp++ = *bp++ & 037; + } else if (*bp == '\\') { + bp++; + if (*bp == ':' || *bp == '\0') + break; /* drop unfinished escape */ + if ('0' <= *bp && *bp <= '7') { + int n, i; + + n = 0; + i = 3; /* maximum of three octal digits */ + do { + n = n * 8 + (*bp++ - '0'); + } while (--i && '0' <= *bp && *bp <= '7'); + *mp++ = n; + } + else switch (*bp++) { + case 'b': case 'B': + *mp++ = '\b'; + break; + case 't': case 'T': + *mp++ = '\t'; + break; + case 'n': case 'N': + *mp++ = '\n'; + break; + case 'f': case 'F': + *mp++ = '\f'; + break; + case 'r': case 'R': + *mp++ = '\r'; + break; + case 'e': case 'E': + *mp++ = ESC; + break; + case 'c': case 'C': + *mp++ = ':'; + break; + default: + /* + * Catches '\', '^', and + * everything else. + */ + *mp++ = *(bp-1); + break; + } + } else + *mp++ = *bp++; + m_room--; + + /* + * Enforce loop invariant: if no room left in current + * buffer, try to get some more. + */ + if (m_room == 0) { + size_t size = mp - mem; + + if ((mem = reallocf(mem, size + SFRAG)) == NULL) + return (-2); + m_room = SFRAG; + mp = mem + size; + } + } + *mp++ = '\0'; /* loop invariant let's us do this */ + m_room--; + len = mp - mem - 1; + + /* + * Give back any extra memory and return value and success. + */ + if (m_room != 0) + if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) + return (-2); + *str = mem; + return (len); +} + +/* + * Cgetustr retrieves the value of the string capability cap from the + * capability record pointed to by buf. The difference between cgetustr() + * and cgetstr() is that cgetustr does not decode escapes but rather treats + * all characters literally. A pointer to a NUL terminated malloc'd + * copy of the string is returned in the char pointed to by str. The + * length of the string not including the trailing NUL is returned on success, + * -1 if the requested string capability couldn't be found, -2 if a system + * error was encountered (storage allocation failure). + */ +int +cgetustr(char *buf, const char *cap, char **str) +{ + u_int m_room; + char *bp, *mp; + int len; + char *mem; + + /* + * Find string capability cap + */ + if ((bp = cgetcap(buf, cap, '=')) == NULL) + return (-1); + + /* + * Conversion / storage allocation loop ... Allocate memory in + * chunks SFRAG in size. + */ + if ((mem = malloc(SFRAG)) == NULL) { + errno = ENOMEM; + return (-2); /* couldn't even allocate the first fragment */ + } + m_room = SFRAG; + mp = mem; + + while (*bp != ':' && *bp != '\0') { + /* + * Loop invariants: + * There is always room for one more character in mem. + * Mp always points just past last character in mem. + * Bp always points at next character in buf. + */ + *mp++ = *bp++; + m_room--; + + /* + * Enforce loop invariant: if no room left in current + * buffer, try to get some more. + */ + if (m_room == 0) { + size_t size = mp - mem; + + if ((mem = reallocf(mem, size + SFRAG)) == NULL) + return (-2); + m_room = SFRAG; + mp = mem + size; + } + } + *mp++ = '\0'; /* loop invariant let's us do this */ + m_room--; + len = mp - mem - 1; + + /* + * Give back any extra memory and return value and success. + */ + if (m_room != 0) + if ((mem = reallocf(mem, (size_t)(mp - mem))) == NULL) + return (-2); + *str = mem; + return (len); +} + +/* + * Cgetnum retrieves the value of the numeric capability cap from the + * capability record pointed to by buf. The numeric value is returned in + * the long pointed to by num. 0 is returned on success, -1 if the requested + * numeric capability couldn't be found. + */ +int +cgetnum(char *buf, const char *cap, long *num) +{ + long n; + int base, digit; + char *bp; + + /* + * Find numeric capability cap + */ + bp = cgetcap(buf, cap, '#'); + if (bp == NULL) + return (-1); + + /* + * Look at value and determine numeric base: + * 0x... or 0X... hexadecimal, + * else 0... octal, + * else decimal. + */ + if (*bp == '0') { + bp++; + if (*bp == 'x' || *bp == 'X') { + bp++; + base = 16; + } else + base = 8; + } else + base = 10; + + /* + * Conversion loop ... + */ + n = 0; + for (;;) { + if ('0' <= *bp && *bp <= '9') + digit = *bp - '0'; + else if ('a' <= *bp && *bp <= 'f') + digit = 10 + *bp - 'a'; + else if ('A' <= *bp && *bp <= 'F') + digit = 10 + *bp - 'A'; + else + break; + + if (digit >= base) + break; + + n = n * base + digit; + bp++; + } + + /* + * Return value and success. + */ + *num = n; + return (0); +} + + +/* + * Compare name field of record. + */ +static int +nfcmp(char *nf, char *rec) +{ + char *cp, tmp; + int ret; + + for (cp = rec; *cp != ':'; cp++) + ; + + tmp = *(cp + 1); + *(cp + 1) = '\0'; + ret = strcmp(nf, rec); + *(cp + 1) = tmp; + + return (ret); +} diff --git a/lib/libc/gen/getcontext.3 b/lib/libc/gen/getcontext.3 new file mode 100644 index 000000000000..db6d5ddcb00d --- /dev/null +++ b/lib/libc/gen/getcontext.3 @@ -0,0 +1,180 @@ +.\" Copyright (c) 2002 Packet Design, LLC. +.\" All rights reserved. +.\" +.\" Subject to the following obligations and disclaimer of warranty, +.\" use and redistribution of this software, in source or object code +.\" forms, with or without modifications are expressly permitted by +.\" Packet Design; provided, however, that: +.\" +.\" (i) Any and all reproductions of the source or object code +.\" must include the copyright notice above and the following +.\" disclaimer of warranties; and +.\" (ii) No rights are granted, in any manner or form, to use +.\" Packet Design trademarks, including the mark "PACKET DESIGN" +.\" on advertising, endorsements, or otherwise except as such +.\" appears in the above copyright notice or in the software. +.\" +.\" THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND +.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO +.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING +.\" THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +.\" OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, +.\" OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS +.\" OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, +.\" RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE +.\" LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE +.\" OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL +.\" DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF +.\" USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +.\" THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF +.\" THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd March 23, 2020 +.Dt GETCONTEXT 3 +.Os +.Sh NAME +.Nm getcontext , getcontextx , setcontext +.Nd get and set user thread context +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In ucontext.h +.Ft int +.Fn getcontext "ucontext_t *ucp" +.Ft ucontext_t * +.Fn getcontextx "void" +.Ft int +.Fn setcontext "const ucontext_t *ucp" +.Sh DESCRIPTION +The +.Fn getcontext +function +saves the current thread's execution context in the structure pointed to by +.Fa ucp . +This saved context may then later be restored by calling +.Fn setcontext . +.Pp +The +.Fn getcontextx +function saves the current execution context in the newly allocated structure +.Vt ucontext_t , +which is returned on success. +If architecture defines additional CPU states that can be stored in extended +blocks referenced from the +.Vt ucontext_t , +the memory for them may be allocated and their context also stored. +Memory returned by +.Fn getcontextx +function shall be freed using +.Fn free 3 . +.Pp +The +.Fn setcontext +function +makes a previously saved thread context the current thread context, i.e., +the current context is lost and +.Fn setcontext +does not return. +Instead, execution continues in the context specified by +.Fa ucp , +which must have been previously initialized by a call to +.Fn getcontext , +.Xr makecontext 3 , +or by being passed as an argument to a signal handler (see +.Xr sigaction 2 ) . +.Pp +If +.Fa ucp +was initialized by +.Fn getcontext , +then execution continues as if the original +.Fn getcontext +call had just returned (again). +.Pp +If +.Fa ucp +was initialized by +.Xr makecontext 3 , +execution continues with the invocation of the function specified to +.Xr makecontext 3 . +When that function returns, +.Fa "ucp->uc_link" +determines what happens next: +if +.Fa "ucp->uc_link" +is +.Dv NULL , +the process exits; +otherwise, +.Fn setcontext "ucp->uc_link" +is implicitly invoked. +.Pp +If +.Fa ucp +was initialized by the invocation of a signal handler, execution continues +at the point the thread was interrupted by the signal. +.Sh RETURN VALUES +If successful, +.Fn getcontext +returns zero and +.Fn setcontext +does not return; otherwise \-1 is returned. +The +.Fn getcontextx +returns pointer to the allocated and initialized context on success, and +.Va NULL +on failure. +.Sh ERRORS +No errors are defined for +.Fn getcontext +or +.Fn setcontext . +The +.Fn getcontextx +may return the following errors in +.Va errno : +.Bl -tag -width Er +.It Bq Er ENOMEM +No memory was available to allocate for the context or some extended state. +.El +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr sigaltstack 2 , +.Xr makecontext 3 , +.Xr ucontext 3 +.Sh STANDARDS +The +.Fn getcontext +and +.Fn setcontext +functions conform to +.St -xsh5 +and +.St -p1003.1-2001 . +The +.Va errno +indications are an extension to the standard. +.Pp +The +.St -p1003.1-2004 +revision marked the functions +.Fn getcontext +and +.Fn setcontext +as obsolete, citing portability issues and recommending the use of +.Tn POSIX +threads instead. +The +.St -p1003.1-2008 +revision removed the functions from the specification. +.Sh HISTORY +The +.Fn getcontext +and +.Fn setcontext +functions first appeared in +.At V.4 . diff --git a/lib/libc/gen/getcwd.3 b/lib/libc/gen/getcwd.3 new file mode 100644 index 000000000000..43d7718e92d6 --- /dev/null +++ b/lib/libc/gen/getcwd.3 @@ -0,0 +1,159 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 17, 2010 +.Dt GETCWD 3 +.Os +.Sh NAME +.Nm getcwd , +.Nm getwd +.Nd get working directory pathname +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft char * +.Fn getcwd "char *buf" "size_t size" +.Ft char * +.Fn getwd "char *buf" +.Sh DESCRIPTION +The +.Fn getcwd +function copies the absolute pathname of the current working directory +into the memory referenced by +.Fa buf +and returns a pointer to +.Fa buf . +The +.Fa size +argument is the size, in bytes, of the array referenced by +.Fa buf . +.Pp +If +.Fa buf +is +.Dv NULL , +space is allocated as necessary to store the pathname. +This space may later be +.Xr free 3 Ns 'd . +.Pp +The function +.Fn getwd +is a compatibility routine which calls +.Fn getcwd +with its +.Fa buf +argument and a size of +.Dv MAXPATHLEN +(as defined in the include +file +.In sys/param.h ) . +Obviously, +.Fa buf +should be at least +.Dv MAXPATHLEN +bytes in length. +.Pp +These routines have traditionally been used by programs to save the +name of a working directory for the purpose of returning to it. +A much faster and less error-prone method of accomplishing this is to +open the current directory +.Pq Ql .\& +and use the +.Xr fchdir 2 +function to return. +.Sh RETURN VALUES +Upon successful completion, a pointer to the pathname is returned. +Otherwise a +.Dv NULL +pointer is returned and the global variable +.Va errno +is set to indicate the error. +In addition, +.Fn getwd +copies the error message associated with +.Va errno +into the memory referenced by +.Fa buf . +.Sh ERRORS +The +.Fn getcwd +function +will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa size +argument is zero. +.It Bq Er ENOENT +A component of the pathname no longer exists. +.It Bq Er ENOMEM +Insufficient memory is available. +.It Bq Er ERANGE +The +.Fa size +argument is greater than zero but smaller than the length of the pathname +plus 1. +.El +.Pp +The +.Fn getcwd +function +may fail if: +.Bl -tag -width Er +.It Bq Er EACCES +Read or search permission was denied for a component of the pathname. +This is only checked in limited cases, depending on implementation details. +.El +.Sh SEE ALSO +.Xr chdir 2 , +.Xr fchdir 2 , +.Xr malloc 3 , +.Xr strerror 3 +.Sh STANDARDS +The +.Fn getcwd +function +conforms to +.St -p1003.1-90 . +The ability to specify a +.Dv NULL +pointer and have +.Fn getcwd +allocate memory as necessary is an extension. +.Sh HISTORY +The +.Fn getwd +function appeared in +.Bx 4.0 . +.Sh BUGS +The +.Fn getwd +function +does not do sufficient error checking and is not able to return very +long, but valid, paths. +It is provided for compatibility. diff --git a/lib/libc/gen/getcwd.c b/lib/libc/gen/getcwd.c new file mode 100644 index 000000000000..18d8ce668274 --- /dev/null +++ b/lib/libc/gen/getcwd.c @@ -0,0 +1,227 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1991, 1993, 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/stat.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <ssp/ssp.h> +#include "un-namespace.h" + +#include "gen-private.h" + +#define ISDOT(dp) \ + (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ + (dp->d_name[1] == '.' && dp->d_name[2] == '\0'))) + +extern int __getcwd(char *, size_t); + +char * +__ssp_real(getcwd)(char *pt, size_t size) +{ + struct dirent *dp; + DIR *dir = NULL; + dev_t dev; + ino_t ino; + int first; + char *bpt; + struct stat s; + dev_t root_dev; + ino_t root_ino; + size_t ptsize; + int save_errno; + char *ept, c; + int fd; + + /* + * If no buffer specified by the user, allocate one as necessary. + * If a buffer is specified, the size has to be non-zero. The path + * is built from the end of the buffer backwards. + */ + if (pt) { + ptsize = 0; + if (!size) { + errno = EINVAL; + return (NULL); + } + if (size == 1) { + errno = ERANGE; + return (NULL); + } + ept = pt + size; + } else { + if ((pt = malloc(ptsize = PATH_MAX)) == NULL) + return (NULL); + ept = pt + ptsize; + } + if (__getcwd(pt, ept - pt) == 0) { + if (*pt != '/') { + bpt = pt; + ept = pt + strlen(pt) - 1; + while (bpt < ept) { + c = *bpt; + *bpt++ = *ept; + *ept-- = c; + } + } + return (pt); + } + bpt = ept - 1; + *bpt = '\0'; + + /* Save root values, so know when to stop. */ + if (stat("/", &s)) + goto err; + root_dev = s.st_dev; + root_ino = s.st_ino; + + errno = 0; /* XXX readdir has no error return. */ + + for (first = 1;; first = 0) { + /* Stat the current level. */ + if (dir != NULL ? _fstat(_dirfd(dir), &s) : lstat(".", &s)) + goto err; + + /* Save current node values. */ + ino = s.st_ino; + dev = s.st_dev; + + /* Check for reaching root. */ + if (root_dev == dev && root_ino == ino) { + *--bpt = '/'; + /* + * It's unclear that it's a requirement to copy the + * path to the beginning of the buffer, but it's always + * been that way and stuff would probably break. + */ + bcopy(bpt, pt, ept - bpt); + if (dir) + (void) closedir(dir); + return (pt); + } + + /* Open and stat parent directory. */ + fd = _openat(dir != NULL ? _dirfd(dir) : AT_FDCWD, + "..", O_RDONLY | O_CLOEXEC); + if (fd == -1) + goto err; + if (dir) + (void) closedir(dir); + if (!(dir = fdopendir(fd)) || _fstat(_dirfd(dir), &s)) { + _close(fd); + goto err; + } + + /* + * If it's a mount point, have to stat each element because + * the inode number in the directory is for the entry in the + * parent directory, not the inode number of the mounted file. + */ + save_errno = 0; + if (s.st_dev == dev) { + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (dp->d_fileno == ino) + break; + } + } else + for (;;) { + if (!(dp = readdir(dir))) + goto notfound; + if (ISDOT(dp)) + continue; + + /* Save the first error for later. */ + if (fstatat(_dirfd(dir), dp->d_name, &s, + AT_SYMLINK_NOFOLLOW)) { + if (!save_errno) + save_errno = errno; + errno = 0; + continue; + } + if (s.st_dev == dev && s.st_ino == ino) + break; + } + + /* + * Check for length of the current name, preceding slash, + * leading slash. + */ + while (bpt - pt < dp->d_namlen + (first ? 1 : 2)) { + size_t len, off; + + if (!ptsize) { + errno = ERANGE; + goto err; + } + off = bpt - pt; + len = ept - bpt; + if ((pt = reallocf(pt, ptsize *= 2)) == NULL) + goto err; + bpt = pt + off; + ept = pt + ptsize; + bcopy(bpt, ept - len, len); + bpt = ept - len; + } + if (!first) + *--bpt = '/'; + bpt -= dp->d_namlen; + bcopy(dp->d_name, bpt, dp->d_namlen); + } + +notfound: + /* + * If readdir set errno, use it, not any saved error; otherwise, + * didn't find the current directory in its parent directory, set + * errno to ENOENT. + */ + if (!errno) + errno = save_errno ? save_errno : ENOENT; + /* FALLTHROUGH */ +err: + save_errno = errno; + + if (ptsize) + free(pt); + if (dir) + (void) closedir(dir); + + errno = save_errno; + return (NULL); +} diff --git a/lib/libc/gen/getdiskbyname.3 b/lib/libc/gen/getdiskbyname.3 new file mode 100644 index 000000000000..8de4f3976dd2 --- /dev/null +++ b/lib/libc/gen/getdiskbyname.3 @@ -0,0 +1,60 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 4, 1993 +.Dt GETDISKBYNAME 3 +.Os +.Sh NAME +.Nm getdiskbyname +.Nd get generic disk description by its name +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/disklabel.h +.Ft struct disklabel * +.Fn getdiskbyname "const char *name" +.Sh DESCRIPTION +The +.Fn getdiskbyname +function +takes a disk name (e.g.\& +.Ql rm03 ) +and returns a prototype disk label +describing its geometry information and the standard +disk partition tables. +All information is obtained from +the +.Xr disktab 5 +file. +.Sh SEE ALSO +.Xr disktab 5 , +.Xr disklabel 8 +.Sh HISTORY +The +.Fn getdiskbyname +function appeared in +.Bx 4.3 . diff --git a/lib/libc/gen/getdomainname.3 b/lib/libc/gen/getdomainname.3 new file mode 100644 index 000000000000..47fb139ac23c --- /dev/null +++ b/lib/libc/gen/getdomainname.3 @@ -0,0 +1,97 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 6, 1994 +.Dt GETDOMAINNAME 3 +.Os +.Sh NAME +.Nm getdomainname , +.Nm setdomainname +.Nd get/set the NIS domain name of current host +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn getdomainname "char *name" "int namelen" +.Ft int +.Fn setdomainname "const char *name" "int namelen" +.Sh DESCRIPTION +The +.Fn getdomainname +function +returns the standard NIS domain name for the current host, as +previously set by +.Fn setdomainname . +The +.Fa namelen +argument +specifies the size of the +.Fa name +array. +The returned name is null-terminated unless insufficient +space is provided. +.Pp +The +.Fn setdomainname +function +sets the NIS domain name of the host machine to be +.Fa name , +which has length +.Fa namelen . +This call is restricted to the super-user and +is normally used only when the system is bootstrapped. +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The following errors may be returned by these calls: +.Bl -tag -width Er +.It Bq Er EFAULT +The +.Fa name +or +.Fa namelen +argument gave an +invalid address. +.It Bq Er EPERM +The caller tried to set the hostname and was not the super-user. +.El +.Sh SEE ALSO +.Xr gethostid 3 , +.Xr gethostname 3 , +.Xr sysctl 3 +.Sh HISTORY +The +.Fn getdomainname +function appeared in +.Bx 4.2 . +.Sh BUGS +Domain names are limited to +.Dv MAXHOSTNAMELEN +(from +.In sys/param.h ) +characters, currently 256. diff --git a/lib/libc/gen/getdomainname.c b/lib/libc/gen/getdomainname.c new file mode 100644 index 000000000000..c0be7465f967 --- /dev/null +++ b/lib/libc/gen/getdomainname.c @@ -0,0 +1,50 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <unistd.h> +#include <ssp/ssp.h> + +int +__ssp_real(getdomainname)(char *name, int namelen) +{ + int mib[2]; + size_t size; + + mib[0] = CTL_KERN; + mib[1] = KERN_NISDOMAINNAME; + size = namelen; + if (sysctl(mib, 2, name, &size, NULL, 0) == -1) + return (-1); + return (0); +} diff --git a/lib/libc/gen/getentropy.3 b/lib/libc/gen/getentropy.3 new file mode 100644 index 000000000000..5f7ee32ebbfc --- /dev/null +++ b/lib/libc/gen/getentropy.3 @@ -0,0 +1,82 @@ +.\" $OpenBSD: getentropy.2,v 1.8 2015/01/31 00:20:12 schwarze Exp $ +.\" +.\" Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org> +.\" Copyright (c) 2014 Theo de Raadt +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.Dd January 17, 2025 +.Dt GETENTROPY 3 +.Os +.Sh NAME +.Nm getentropy +.Nd get entropy +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn getentropy "void *buf" "size_t buflen" +.Sh DESCRIPTION +.Fn getentropy +fills a buffer with high-quality random data. +.Pp +The maximum +.Fa buflen +permitted is 256 bytes. +.Pp +If it does not produce an error, +.Fn getentropy +always provides the requested number of bytes of random data. +.Pp +Similar to reading from +.Pa /dev/urandom +just after boot, +.Fn getentropy +may block until the system has collected enough entropy to seed the CSPRNG. +.Sh IMPLEMENTATION NOTES +The +.Fn getentropy +function is implemented using +.Xr getrandom 2 . +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +.Fn getentropy +will succeed unless: +.Bl -tag -width Er +.It Bq Er EFAULT +The +.Fa buf +parameter points to an +invalid address. +.It Bq Er EINVAL +Too many bytes requested. +.El +.Sh SEE ALSO +.Xr getrandom 2 , +.Xr arc4random 3 , +.Xr random 4 +.Sh STANDARDS +.Fn getentropy +conforms to +.St -p1003.1-2024 . +.Sh HISTORY +The +.Fn getentropy +function appeared in +.Ox 5.6 . +The +.Fx +libc compatibility shim first appeared in +.Fx 12.0 . diff --git a/lib/libc/gen/getentropy.c b/lib/libc/gen/getentropy.c new file mode 100644 index 000000000000..6b8ad697b7e0 --- /dev/null +++ b/lib/libc/gen/getentropy.c @@ -0,0 +1,78 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2018 Conrad Meyer <cem@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/random.h> + +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <unistd.h> +#include <ssp/ssp.h> + +#include "libc_private.h" + +static inline void +_getentropy_fail(void) +{ + raise(SIGKILL); +} + +int +__ssp_real(getentropy)(void *buf, size_t buflen) +{ + ssize_t rd; + + if (buflen > GETENTROPY_MAX) { + errno = EINVAL; + return (-1); + } + + while (buflen > 0) { + rd = getrandom(buf, buflen, 0); + if (rd == -1) { + switch (errno) { + case EINTR: + continue; + case EFAULT: + return (-1); + default: + _getentropy_fail(); + } + } + + /* This cannot happen. */ + if (rd == 0) + _getentropy_fail(); + + buf = (char *)buf + rd; + buflen -= rd; + } + + return (0); +} diff --git a/lib/libc/gen/getfsent.3 b/lib/libc/gen/getfsent.3 new file mode 100644 index 000000000000..4783c7469910 --- /dev/null +++ b/lib/libc/gen/getfsent.3 @@ -0,0 +1,182 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 7, 2003 +.Dt GETFSENT 3 +.Os +.Sh NAME +.Nm getfsent , +.Nm getfsspec , +.Nm getfsfile , +.Nm setfsent , +.Nm endfsent +.Nd get file system descriptor file entry +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In fstab.h +.Ft "struct fstab *" +.Fn getfsent void +.Ft "struct fstab *" +.Fn getfsspec "const char *spec" +.Ft "struct fstab *" +.Fn getfsfile "const char *file" +.Ft int +.Fn setfsent void +.Ft void +.Fn endfsent void +.Ft void +.Fn setfstab "const char *file" +.Ft "const char *" +.Fn getfstab void +.Sh DESCRIPTION +The +.Fn getfsent , +.Fn getfsspec , +and +.Fn getfsfile +functions +each return a pointer to an object with the following structure +containing the broken-out fields of a line in the file system +description file, +.In fstab.h . +.Bd -literal -offset indent +struct fstab { + char *fs_spec; /* block special device name */ + char *fs_file; /* file system path prefix */ + char *fs_vfstype; /* File system type, ufs, nfs */ + char *fs_mntops; /* Mount options ala -o */ + char *fs_type; /* FSTAB_* from fs_mntops */ + int fs_freq; /* dump frequency, in days */ + int fs_passno; /* pass number on parallel fsck */ +}; +.Ed +.Pp +The fields have meanings described in +.Xr fstab 5 . +.Pp +The +.Fn setfsent +function +opens the file (closing any previously opened file) or rewinds it +if it is already open. +.Pp +The +.Fn endfsent +function +closes the file. +.Pp +The +.Fn setfstab +function sets the file to be used by subsequent operations. +The value set by +.Fn setfstab +does not persist across calls to +.Fn endfsent . +.Pp +The +.Fn getfstab +function returns the name of the file that will be used. +.Pp +The +.Fn getfsspec +and +.Fn getfsfile +functions +search the entire file (opening it if necessary) for a matching special +file name or file system file name. +.Pp +For programs wishing to read the entire database, +.Fn getfsent +reads the next entry (opening the file if necessary). +.Pp +All entries in the file with a type field equivalent to +.Dv FSTAB_XX +are ignored. +.Sh RETURN VALUES +The +.Fn getfsent , +.Fn getfsspec , +and +.Fn getfsfile +functions +return a +.Dv NULL +pointer on +.Dv EOF +or error. +The +.Fn setfsent +function +returns 0 on failure, 1 on success. +The +.Fn endfsent +function +returns nothing. +.Sh ENVIRONMENT +.Bl -tag -width ".Ev PATH_FSTAB" +.It Ev PATH_FSTAB +If the environment variable +.Ev PATH_FSTAB +is set, all operations are performed against the specified file. +.Ev PATH_FSTAB +will not be honored if the process environment or memory address space is +considered +.Dq tainted . +(See +.Xr issetugid 2 +for more information.) +.El +.Sh FILES +.Bl -tag -width /etc/fstab -compact +.It Pa /etc/fstab +.El +.Sh SEE ALSO +.Xr fstab 5 +.Sh HISTORY +The +.Fn getfsent +function appeared in +.Bx 4.0 ; +the +.Fn endfsent , +.Fn getfsfile , +.Fn getfsspec , +and +.Fn setfsent +functions appeared in +.Bx 4.3 ; +the +.Fn setfstab +and +.Fn getfstab +functions appeared in +.Fx 5.1 . +.Sh BUGS +These functions use static data storage; +if the data is needed for future use, it should be +copied before any subsequent calls overwrite it. diff --git a/lib/libc/gen/getgrent.3 b/lib/libc/gen/getgrent.3 new file mode 100644 index 000000000000..e4a703f3bfad --- /dev/null +++ b/lib/libc/gen/getgrent.3 @@ -0,0 +1,283 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 31, 2016 +.Dt GETGRENT 3 +.Os +.Sh NAME +.Nm getgrent , +.Nm getgrent_r , +.Nm getgrnam , +.Nm getgrnam_r , +.Nm getgrgid , +.Nm getgrgid_r , +.Nm setgroupent , +.Nm setgrent , +.Nm endgrent +.Nd group database operations +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In grp.h +.Ft struct group * +.Fn getgrent void +.Ft int +.Fn getgrent_r "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result" +.Ft struct group * +.Fn getgrnam "const char *name" +.Ft int +.Fn getgrnam_r "const char *name" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result" +.Ft struct group * +.Fn getgrgid "gid_t gid" +.Ft int +.Fn getgrgid_r "gid_t gid" "struct group *grp" "char *buffer" "size_t bufsize" "struct group **result" +.Ft int +.Fn setgroupent "int stayopen" +.Ft void +.Fn setgrent void +.Ft void +.Fn endgrent void +.Sh DESCRIPTION +These functions operate on the group database file +.Pa /etc/group +which is described +in +.Xr group 5 . +Each line of the database is defined by the structure +.Vt group +found in the include +file +.In grp.h : +.Bd -literal -offset indent +struct group { + char *gr_name; /* group name */ + char *gr_passwd; /* group password */ + gid_t gr_gid; /* group id */ + char **gr_mem; /* group members */ +}; +.Ed +.Pp +The functions +.Fn getgrnam +and +.Fn getgrgid +search the group database for the given group name pointed to by +.Fa name +or the group id pointed to by +.Fa gid , +respectively, returning the first one encountered. +Identical group +names or group gids may result in undefined behavior. +.Pp +The +.Fn getgrent +function +sequentially reads the group database and is intended for programs +that wish to step through the complete list of groups. +.Pp +The functions +.Fn getgrent_r , +.Fn getgrnam_r , +and +.Fn getgrgid_r +are thread-safe versions of +.Fn getgrent , +.Fn getgrnam , +and +.Fn getgrgid , +respectively. +The caller must provide storage for the results of the search in +the +.Fa grp , +.Fa buffer , +.Fa bufsize , +and +.Fa result +arguments. +When these functions are successful, the +.Fa grp +argument will be filled-in, and a pointer to that argument will be +stored in +.Fa result . +If an entry is not found or an error occurs, +.Fa result +will be set to +.Dv NULL . +.Pp +These functions will open the group file for reading, if necessary. +.Pp +The +.Fn setgroupent +function +opens the file, or rewinds it if it is already open. +If +.Fa stayopen +is non-zero, file descriptors are left open, significantly speeding +functions subsequent calls. +This functionality is unnecessary for +.Fn getgrent +as it does not close its file descriptors by default. +It should also +be noted that it is dangerous for long-running programs to use this +functionality as the group file may be updated. +.Pp +The +.Fn setgrent +function +is identical to +.Fn setgroupent +with an argument of zero. +.Pp +The +.Fn endgrent +function +closes any open files. +.Sh RETURN VALUES +The functions +.Fn getgrent , +.Fn getgrnam , +and +.Fn getgrgid , +return a pointer to a group structure on success or +.Dv NULL +if the entry is not found or if an error occurs. +If an error does occur, +.Va errno +will be set. +Note that programs must explicitly set +.Va errno +to zero before calling any of these functions if they need to +distinguish between a non-existent entry and an error. +The functions +.Fn getgrent_r , +.Fn getgrnam_r , +and +.Fn getgrgid_r +return 0 if no error occurred, or an error number to indicate failure. +It is not an error if a matching entry is not found. +(Thus, if +.Fa result +is set to +.Dv NULL +and the return value is 0, no matching entry exists.) +.Pp +The function +.Fn setgroupent +returns the value 1 if successful, otherwise the value +0 is returned. +The functions +.Fn endgrent , +.Fn setgrent +and +.Fn setgrfile +have no return value. +.Sh FILES +.Bl -tag -width /etc/group -compact +.It Pa /etc/group +group database file +.El +.Sh COMPATIBILITY +The historic function +.Fn setgrfile , +which allowed the specification of alternate password databases, has +been deprecated and is no longer available. +.Sh SEE ALSO +.Xr getpwent 3 , +.Xr group 5 , +.Xr nsswitch.conf 5 , +.Xr yp 8 +.Sh STANDARDS +The +.Fn getgrent , +.Fn getgrnam , +.Fn getgrnam_r , +.Fn getgrgid , +.Fn getgrgid_r +and +.Fn endgrent +functions conform to +.St -p1003.1-96 . +The +.Fn setgrent +function differs from that standard in that its return type is +.Vt int +rather than +.Vt void . +.Sh HISTORY +The functions +.Fn endgrent , +.Fn getgrent , +.Fn getgrnam , +.Fn getgrgid , +and +.Fn setgrent +appeared in +.At v7 . +The functions +.Fn setgrfile +and +.Fn setgroupent +appeared in +.Bx 4.3 Reno . +The functions +.Fn getgrent_r , +.Fn getgrnam_r , +and +.Fn getgrgid_r +appeared in +.Fx 5.1 . +.Sh BUGS +The functions +.Fn getgrent , +.Fn getgrnam , +.Fn getgrgid , +.Fn setgroupent +and +.Fn setgrent +leave their results in an internal static object and return +a pointer to that object. +Subsequent calls to +the same function +will modify the same object. +.Pp +The functions +.Fn getgrent , +.Fn getgrent_r , +.Fn endgrent , +.Fn setgroupent , +and +.Fn setgrent +are fairly useless in a networked environment and should be +avoided, if possible. +The +.Fn getgrent +and +.Fn getgrent_r +functions +make no attempt to suppress duplicate information if multiple +sources are specified in +.Xr nsswitch.conf 5 . diff --git a/lib/libc/gen/getgrent.c b/lib/libc/gen/getgrent.c new file mode 100644 index 000000000000..508e3d63eb60 --- /dev/null +++ b/lib/libc/gen/getgrent.c @@ -0,0 +1,1575 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2003 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by + * Jacques A. Vidrine, Safeport Network Services, and Network + * Associates Laboratories, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include "namespace.h" +#include <sys/param.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#ifdef HESIOD +#include <hesiod.h> +#endif +#include <grp.h> +#include <nsswitch.h> +#include <pthread.h> +#include <pthread_np.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include "un-namespace.h" +#include "libc_private.h" +#include "nss_tls.h" +#ifdef NS_CACHING +#include "nscache.h" +#endif + +enum constants { + GRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ + GRP_STORAGE_MAX = 1 << 20, /* 1 MByte */ + SETGRENT = 1, + ENDGRENT = 2, + HESIOD_NAME_MAX = 256, +}; + +static const ns_src defaultsrc[] = { + { NSSRC_COMPAT, NS_SUCCESS }, + { NULL, 0 } +}; + +int __getgroupmembership(const char *, gid_t, gid_t *, int, int *); +int __gr_match_entry(const char *, size_t, enum nss_lookup_type, + const char *, gid_t); +int __gr_parse_entry(char *, size_t, struct group *, char *, size_t, + int *); + +static int is_comment_line(const char *, size_t); + +union key { + const char *name; + gid_t gid; +}; +static struct group *getgr(int (*)(union key, struct group *, char *, size_t, + struct group **), union key); +static int wrap_getgrnam_r(union key, struct group *, char *, size_t, + struct group **); +static int wrap_getgrgid_r(union key, struct group *, char *, size_t, + struct group **); +static int wrap_getgrent_r(union key, struct group *, char *, size_t, + struct group **); + +struct files_state { + FILE *fp; + int stayopen; +}; +static void files_endstate(void *); +NSS_TLS_HANDLING(files); +static int files_setgrent(void *, void *, va_list); +static int files_group(void *, void *, va_list); + + +#ifdef HESIOD +struct dns_state { + long counter; +}; +static void dns_endstate(void *); +NSS_TLS_HANDLING(dns); +static int dns_setgrent(void *, void *, va_list); +static int dns_group(void *, void *, va_list); +#endif + + +#ifdef YP +struct nis_state { + char domain[MAXHOSTNAMELEN]; + int done; + char *key; + int keylen; +}; +static void nis_endstate(void *); +NSS_TLS_HANDLING(nis); +static int nis_setgrent(void *, void *, va_list); +static int nis_group(void *, void *, va_list); +#endif + +struct compat_state { + FILE *fp; + int stayopen; + char *name; + enum _compat { + COMPAT_MODE_OFF = 0, + COMPAT_MODE_ALL, + COMPAT_MODE_NAME + } compat; +}; +static void compat_endstate(void *); +NSS_TLS_HANDLING(compat); +static int compat_setgrent(void *, void *, va_list); +static int compat_group(void *, void *, va_list); + +static int gr_addgid(gid_t, gid_t *, int, int *); +static int getgroupmembership_fallback(void *, void *, va_list); + +#ifdef NS_CACHING +static int grp_id_func(char *, size_t *, va_list, void *); +static int grp_marshal_func(char *, size_t *, void *, va_list, void *); +static int grp_unmarshal_func(char *, size_t, void *, va_list, void *); + +static int +grp_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) +{ + char *name; + gid_t gid; + + size_t desired_size, size; + int res = NS_UNAVAIL; + enum nss_lookup_type lookup_type; + + + lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata; + switch (lookup_type) { + case nss_lt_name: + name = va_arg(ap, char *); + size = strlen(name); + desired_size = sizeof(enum nss_lookup_type) + size + 1; + if (desired_size > *buffer_size) { + res = NS_RETURN; + goto fin; + } + + memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); + memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); + + res = NS_SUCCESS; + break; + case nss_lt_id: + gid = va_arg(ap, gid_t); + desired_size = sizeof(enum nss_lookup_type) + sizeof(gid_t); + if (desired_size > *buffer_size) { + res = NS_RETURN; + goto fin; + } + + memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); + memcpy(buffer + sizeof(enum nss_lookup_type), &gid, + sizeof(gid_t)); + + res = NS_SUCCESS; + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + +fin: + *buffer_size = desired_size; + return (res); +} + +static int +grp_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, + void *cache_mdata) +{ + char *name __unused; + gid_t gid __unused; + struct group *grp; + char *orig_buf __unused; + size_t orig_buf_size __unused; + struct group new_grp; + size_t desired_size, size, mem_size; + char *p, **mem; + + switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + gid = va_arg(ap, gid_t); + break; + case nss_lt_all: + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + + grp = va_arg(ap, struct group *); + orig_buf = va_arg(ap, char *); + orig_buf_size = va_arg(ap, size_t); + + desired_size = _ALIGNBYTES + sizeof(struct group) + sizeof(char *); + + if (grp->gr_name != NULL) + desired_size += strlen(grp->gr_name) + 1; + if (grp->gr_passwd != NULL) + desired_size += strlen(grp->gr_passwd) + 1; + + if (grp->gr_mem != NULL) { + mem_size = 0; + for (mem = grp->gr_mem; *mem; ++mem) { + desired_size += strlen(*mem) + 1; + ++mem_size; + } + + desired_size += _ALIGNBYTES + (mem_size + 1) * sizeof(char *); + } + + if (desired_size > *buffer_size) { + /* this assignment is here for future use */ + *buffer_size = desired_size; + return (NS_RETURN); + } + + memcpy(&new_grp, grp, sizeof(struct group)); + memset(buffer, 0, desired_size); + + *buffer_size = desired_size; + p = buffer + sizeof(struct group) + sizeof(char *); + memcpy(buffer + sizeof(struct group), &p, sizeof(char *)); + p = (char *)_ALIGN(p); + + if (new_grp.gr_name != NULL) { + size = strlen(new_grp.gr_name); + memcpy(p, new_grp.gr_name, size); + new_grp.gr_name = p; + p += size + 1; + } + + if (new_grp.gr_passwd != NULL) { + size = strlen(new_grp.gr_passwd); + memcpy(p, new_grp.gr_passwd, size); + new_grp.gr_passwd = p; + p += size + 1; + } + + if (new_grp.gr_mem != NULL) { + p = (char *)_ALIGN(p); + memcpy(p, new_grp.gr_mem, sizeof(char *) * mem_size); + new_grp.gr_mem = (char **)p; + p += sizeof(char *) * (mem_size + 1); + + for (mem = new_grp.gr_mem; *mem; ++mem) { + size = strlen(*mem); + memcpy(p, *mem, size); + *mem = p; + p += size + 1; + } + } + + memcpy(buffer, &new_grp, sizeof(struct group)); + return (NS_SUCCESS); +} + +static int +grp_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, + void *cache_mdata) +{ + char *name __unused; + gid_t gid __unused; + struct group *grp; + char *orig_buf; + size_t orig_buf_size; + int *ret_errno; + + char *p; + char **mem; + + switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + gid = va_arg(ap, gid_t); + break; + case nss_lt_all: + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + + grp = va_arg(ap, struct group *); + orig_buf = va_arg(ap, char *); + orig_buf_size = va_arg(ap, size_t); + ret_errno = va_arg(ap, int *); + + if (orig_buf_size + sizeof(struct group) + sizeof(char *) < buffer_size) + { + *ret_errno = ERANGE; + return (NS_RETURN); + } else if (buffer_size < sizeof(struct group) + sizeof(char *)) { + /* + * nscd(8) sometimes returns buffer_size=1 for nonexistent + * entries. + */ + *ret_errno = 0; + return (NS_NOTFOUND); + } + + memcpy(grp, buffer, sizeof(struct group)); + memcpy(&p, buffer + sizeof(struct group), sizeof(char *)); + + if (orig_buf_size + sizeof(struct group) + sizeof(char *) + + _ALIGN(p) - (size_t)p < buffer_size) { + *ret_errno = ERANGE; + return (NS_RETURN); + } + + orig_buf = (char *)_ALIGN(orig_buf); + memcpy(orig_buf, buffer + sizeof(struct group) + sizeof(char *) + + _ALIGN(p) - (size_t)p, + buffer_size - sizeof(struct group) - sizeof(char *) - + _ALIGN(p) + (size_t)p); + p = (char *)_ALIGN(p); + + NS_APPLY_OFFSET(grp->gr_name, orig_buf, p, char *); + NS_APPLY_OFFSET(grp->gr_passwd, orig_buf, p, char *); + if (grp->gr_mem != NULL) { + NS_APPLY_OFFSET(grp->gr_mem, orig_buf, p, char **); + + for (mem = grp->gr_mem; *mem; ++mem) + NS_APPLY_OFFSET(*mem, orig_buf, p, char *); + } + + if (retval != NULL) + *((struct group **)retval) = grp; + + return (NS_SUCCESS); +} + +NSS_MP_CACHE_HANDLING(group); +#endif /* NS_CACHING */ + +#ifdef NS_CACHING +static const nss_cache_info setgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER( + group, (void *)nss_lt_all, + NULL, NULL); +#endif + +static const ns_dtab setgrent_dtab[] = { + { NSSRC_FILES, files_setgrent, (void *)SETGRENT }, +#ifdef HESIOD + { NSSRC_DNS, dns_setgrent, (void *)SETGRENT }, +#endif +#ifdef YP + { NSSRC_NIS, nis_setgrent, (void *)SETGRENT }, +#endif + { NSSRC_COMPAT, compat_setgrent, (void *)SETGRENT }, +#ifdef NS_CACHING + NS_CACHE_CB(&setgrent_cache_info) +#endif + { NULL, NULL, NULL } +}; + +#ifdef NS_CACHING +static const nss_cache_info endgrent_cache_info = NS_MP_CACHE_INFO_INITIALIZER( + group, (void *)nss_lt_all, + NULL, NULL); +#endif + +static const ns_dtab endgrent_dtab[] = { + { NSSRC_FILES, files_setgrent, (void *)ENDGRENT }, +#ifdef HESIOD + { NSSRC_DNS, dns_setgrent, (void *)ENDGRENT }, +#endif +#ifdef YP + { NSSRC_NIS, nis_setgrent, (void *)ENDGRENT }, +#endif + { NSSRC_COMPAT, compat_setgrent, (void *)ENDGRENT }, +#ifdef NS_CACHING + NS_CACHE_CB(&endgrent_cache_info) +#endif + { NULL, NULL, NULL } +}; + +#ifdef NS_CACHING +static const nss_cache_info getgrent_r_cache_info = NS_MP_CACHE_INFO_INITIALIZER( + group, (void *)nss_lt_all, + grp_marshal_func, grp_unmarshal_func); +#endif + +static const ns_dtab getgrent_r_dtab[] = { + { NSSRC_FILES, files_group, (void *)nss_lt_all }, +#ifdef HESIOD + { NSSRC_DNS, dns_group, (void *)nss_lt_all }, +#endif +#ifdef YP + { NSSRC_NIS, nis_group, (void *)nss_lt_all }, +#endif + { NSSRC_COMPAT, compat_group, (void *)nss_lt_all }, +#ifdef NS_CACHING + NS_CACHE_CB(&getgrent_r_cache_info) +#endif + { NULL, NULL, NULL } +}; + +static int +gr_addgid(gid_t gid, gid_t *groups, int maxgrp, int *grpcnt) +{ + int ret, dupc; + + for (dupc = 1; dupc < MIN(maxgrp, *grpcnt); dupc++) { + if (groups[dupc] == gid) + return 1; + } + + ret = 1; + if (*grpcnt < maxgrp) + groups[*grpcnt] = gid; + else + ret = 0; + + (*grpcnt)++; + + return ret; +} + +static int +getgroupmembership_fallback(void *retval, void *mdata, va_list ap) +{ + const ns_src src[] = { + { mdata, NS_SUCCESS }, + { NULL, 0} + }; + struct group grp; + struct group *grp_p; + char *buf; + size_t bufsize; + const char *uname; + gid_t *groups; + gid_t agroup; + int maxgrp, *grpcnt; + int i, rv, ret_errno; + + /* + * As this is a fallback method, only provided src + * list will be respected during methods search. + */ + assert(src[0].name != NULL); + + uname = va_arg(ap, const char *); + agroup = va_arg(ap, gid_t); + groups = va_arg(ap, gid_t *); + maxgrp = va_arg(ap, int); + grpcnt = va_arg(ap, int *); + + rv = NS_UNAVAIL; + + buf = malloc(GRP_STORAGE_INITIAL); + if (buf == NULL) + goto out; + + bufsize = GRP_STORAGE_INITIAL; + + gr_addgid(agroup, groups, maxgrp, grpcnt); + + _nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", src, 0); + for (;;) { + do { + ret_errno = 0; + grp_p = NULL; + rv = _nsdispatch(&grp_p, getgrent_r_dtab, NSDB_GROUP, + "getgrent_r", src, &grp, buf, bufsize, &ret_errno); + + if (grp_p == NULL && ret_errno == ERANGE) { + free(buf); + if ((bufsize << 1) > GRP_STORAGE_MAX) { + buf = NULL; + errno = ERANGE; + goto out; + } + + bufsize <<= 1; + buf = malloc(bufsize); + if (buf == NULL) { + goto out; + } + } + } while (grp_p == NULL && ret_errno == ERANGE); + + if (ret_errno != 0) { + errno = ret_errno; + goto out; + } + + if (grp_p == NULL) + break; + + for (i = 0; grp.gr_mem[i]; i++) { + if (strcmp(grp.gr_mem[i], uname) == 0) + gr_addgid(grp.gr_gid, groups, maxgrp, grpcnt); + } + } + + _nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", src); +out: + free(buf); + return (rv); +} + +void +setgrent(void) +{ + (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, 0); +} + + +int +setgroupent(int stayopen) +{ + (void)_nsdispatch(NULL, setgrent_dtab, NSDB_GROUP, "setgrent", defaultsrc, + stayopen); + return (1); +} + + +void +endgrent(void) +{ + (void)_nsdispatch(NULL, endgrent_dtab, NSDB_GROUP, "endgrent", defaultsrc); +} + + +int +getgrent_r(struct group *grp, char *buffer, size_t bufsize, + struct group **result) +{ + int rv, ret_errno; + + ret_errno = 0; + *result = NULL; + rv = _nsdispatch(result, getgrent_r_dtab, NSDB_GROUP, "getgrent_r", defaultsrc, + grp, buffer, bufsize, &ret_errno); + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + + +int +getgrnam_r(const char *name, struct group *grp, char *buffer, size_t bufsize, + struct group **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = + NS_COMMON_CACHE_INFO_INITIALIZER( + group, (void *)nss_lt_name, + grp_id_func, grp_marshal_func, grp_unmarshal_func); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_group, (void *)nss_lt_name }, +#ifdef HESIOD + { NSSRC_DNS, dns_group, (void *)nss_lt_name }, +#endif +#ifdef YP + { NSSRC_NIS, nis_group, (void *)nss_lt_name }, +#endif + { NSSRC_COMPAT, compat_group, (void *)nss_lt_name }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + ret_errno = 0; + *result = NULL; + rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrnam_r", defaultsrc, + name, grp, buffer, bufsize, &ret_errno); + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + + +int +getgrgid_r(gid_t gid, struct group *grp, char *buffer, size_t bufsize, + struct group **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = + NS_COMMON_CACHE_INFO_INITIALIZER( + group, (void *)nss_lt_id, + grp_id_func, grp_marshal_func, grp_unmarshal_func); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_group, (void *)nss_lt_id }, +#ifdef HESIOD + { NSSRC_DNS, dns_group, (void *)nss_lt_id }, +#endif +#ifdef YP + { NSSRC_NIS, nis_group, (void *)nss_lt_id }, +#endif + { NSSRC_COMPAT, compat_group, (void *)nss_lt_id }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + ret_errno = 0; + *result = NULL; + rv = _nsdispatch(result, dtab, NSDB_GROUP, "getgrgid_r", defaultsrc, + gid, grp, buffer, bufsize, &ret_errno); + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + + + +int +__getgroupmembership(const char *uname, gid_t agroup, gid_t *groups, + int maxgrp, int *grpcnt) +{ + static const ns_dtab dtab[] = { + NS_FALLBACK_CB(getgroupmembership_fallback) + { NULL, NULL, NULL } + }; + + assert(uname != NULL); + /* groups may be NULL if just sizing when invoked with maxgrp = 0 */ + assert(grpcnt != NULL); + + *grpcnt = 0; + (void)_nsdispatch(NULL, dtab, NSDB_GROUP, "getgroupmembership", + defaultsrc, uname, agroup, groups, maxgrp, grpcnt); + + /* too many groups found? */ + return (*grpcnt > maxgrp ? -1 : 0); +} + + +static struct group grp; +static char *grp_storage; +static size_t grp_storage_size; + +static struct group * +getgr(int (*fn)(union key, struct group *, char *, size_t, struct group **), + union key key) +{ + int rv; + struct group *res; + + if (grp_storage == NULL) { + grp_storage = malloc(GRP_STORAGE_INITIAL); + if (grp_storage == NULL) + return (NULL); + grp_storage_size = GRP_STORAGE_INITIAL; + } + do { + rv = fn(key, &grp, grp_storage, grp_storage_size, &res); + if (res == NULL && rv == ERANGE) { + free(grp_storage); + if ((grp_storage_size << 1) > GRP_STORAGE_MAX) { + grp_storage = NULL; + errno = ERANGE; + return (NULL); + } + grp_storage_size <<= 1; + grp_storage = malloc(grp_storage_size); + if (grp_storage == NULL) + return (NULL); + } + } while (res == NULL && rv == ERANGE); + if (rv != 0) + errno = rv; + return (res); +} + + +static int +wrap_getgrnam_r(union key key, struct group *grp, char *buffer, size_t bufsize, + struct group **res) +{ + return (getgrnam_r(key.name, grp, buffer, bufsize, res)); +} + + +static int +wrap_getgrgid_r(union key key, struct group *grp, char *buffer, size_t bufsize, + struct group **res) +{ + return (getgrgid_r(key.gid, grp, buffer, bufsize, res)); +} + + +static int +wrap_getgrent_r(union key key __unused, struct group *grp, char *buffer, + size_t bufsize, struct group **res) +{ + return (getgrent_r(grp, buffer, bufsize, res)); +} + + +struct group * +getgrnam(const char *name) +{ + union key key; + + key.name = name; + return (getgr(wrap_getgrnam_r, key)); +} + + +struct group * +getgrgid(gid_t gid) +{ + union key key; + + key.gid = gid; + return (getgr(wrap_getgrgid_r, key)); +} + + +struct group * +getgrent(void) +{ + union key key; + + key.gid = 0; /* not used */ + return (getgr(wrap_getgrent_r, key)); +} + + +static int +is_comment_line(const char *s, size_t n) +{ + const char *eom; + + eom = &s[n]; + + for (; s < eom; s++) + if (*s == '#' || !isspace((unsigned char)*s)) + break; + return (*s == '#' || s == eom); +} + + +/* + * files backend + */ +static void +files_endstate(void *p) +{ + + if (p == NULL) + return; + if (((struct files_state *)p)->fp != NULL) + fclose(((struct files_state *)p)->fp); + free(p); +} + + +static int +files_setgrent(void *retval, void *mdata, va_list ap) +{ + struct files_state *st; + int rv, stayopen; + + rv = files_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + switch ((enum constants)(uintptr_t)mdata) { + case SETGRENT: + stayopen = va_arg(ap, int); + if (st->fp != NULL) + rewind(st->fp); + else if (stayopen) + st->fp = fopen(_PATH_GROUP, "re"); + st->stayopen = stayopen; + break; + case ENDGRENT: + if (st->fp != NULL) { + fclose(st->fp); + st->fp = NULL; + } + break; + default: + break; + } + return (NS_UNAVAIL); +} + + +static int +files_group(void *retval, void *mdata, va_list ap) +{ + struct files_state *st; + enum nss_lookup_type how; + const char *name, *line; + struct group *grp; + gid_t gid; + char *buffer; + size_t bufsize, linesize; + off_t pos; + int fresh, rv, stayopen, *errnop; + + fresh = 0; + name = NULL; + gid = (gid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + break; + case nss_lt_id: + gid = va_arg(ap, gid_t); + break; + case nss_lt_all: + break; + default: + return (NS_NOTFOUND); + } + grp = va_arg(ap, struct group *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = files_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (st->fp == NULL) { + st->fp = fopen(_PATH_GROUP, "re"); + if (st->fp == NULL) { + *errnop = errno; + return (NS_UNAVAIL); + } + fresh = 1; + } + stayopen = (how == nss_lt_all || !fresh) ? 1 : st->stayopen; + if (stayopen) + pos = ftello(st->fp); + if (how != nss_lt_all && !fresh) + rewind(st->fp); + rv = NS_NOTFOUND; + while ((line = fgetln(st->fp, &linesize)) != NULL) { + if (line[linesize-1] == '\n') + linesize--; + rv = __gr_match_entry(line, linesize, how, name, gid); + if (rv != NS_SUCCESS) + continue; + /* We need room at least for the line, a string NUL + * terminator, alignment padding, and one (char *) + * pointer for the member list terminator. + */ + if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + memcpy(buffer, line, linesize); + buffer[linesize] = '\0'; + rv = __gr_parse_entry(buffer, linesize, grp, + &buffer[linesize + 1], bufsize - linesize - 1, errnop); + if (rv & NS_TERMINATE) + break; + if (how == nss_lt_all) + pos = ftello(st->fp); + } + if (st->fp != NULL && !stayopen) { + fclose(st->fp); + st->fp = NULL; + } + if (st->fp != NULL && how != nss_lt_all) + fseeko(st->fp, pos, SEEK_SET); + if (rv == NS_SUCCESS && retval != NULL) + *(struct group **)retval = grp; + else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) + fseeko(st->fp, pos, SEEK_SET); + return (rv); +} + + +#ifdef HESIOD +/* + * dns backend + */ +static void +dns_endstate(void *p) +{ + + free(p); +} + + +static int +dns_setgrent(void *retval, void *cb_data, va_list ap) +{ + struct dns_state *st; + int rv; + + rv = dns_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + st->counter = 0; + return (NS_UNAVAIL); +} + + +static int +dns_group(void *retval, void *mdata, va_list ap) +{ + char buf[HESIOD_NAME_MAX]; + struct dns_state *st; + struct group *grp; + const char *name, *label; + void *ctx; + char *buffer, **hes; + size_t bufsize, adjsize, linesize; + gid_t gid; + enum nss_lookup_type how; + int rv, *errnop; + + ctx = NULL; + hes = NULL; + name = NULL; + gid = (gid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + break; + case nss_lt_id: + gid = va_arg(ap, gid_t); + break; + case nss_lt_all: + break; + } + grp = va_arg(ap, struct group *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = dns_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (hesiod_init(&ctx) != 0) { + *errnop = errno; + rv = NS_UNAVAIL; + goto fin; + } + do { + rv = NS_NOTFOUND; + switch (how) { + case nss_lt_name: + label = name; + break; + case nss_lt_id: + if (snprintf(buf, sizeof(buf), "%lu", + (unsigned long)gid) >= sizeof(buf)) + goto fin; + label = buf; + break; + case nss_lt_all: + if (st->counter < 0) + goto fin; + if (snprintf(buf, sizeof(buf), "group-%ld", + st->counter++) >= sizeof(buf)) + goto fin; + label = buf; + break; + } + hes = hesiod_resolve(ctx, label, + how == nss_lt_id ? "gid" : "group"); + if ((how == nss_lt_id && hes == NULL && + (hes = hesiod_resolve(ctx, buf, "group")) == NULL) || + hes == NULL) { + if (how == nss_lt_all) + st->counter = -1; + if (errno != ENOENT) + *errnop = errno; + goto fin; + } + rv = __gr_match_entry(hes[0], strlen(hes[0]), how, name, gid); + if (rv != NS_SUCCESS) { + hesiod_free_list(ctx, hes); + hes = NULL; + continue; + } + /* We need room at least for the line, a string NUL + * terminator, alignment padding, and one (char *) + * pointer for the member list terminator. + */ + adjsize = bufsize - _ALIGNBYTES - sizeof(char *); + linesize = strlcpy(buffer, hes[0], adjsize); + if (linesize >= adjsize) { + *errnop = ERANGE; + rv = NS_RETURN; + goto fin; + } + hesiod_free_list(ctx, hes); + hes = NULL; + rv = __gr_parse_entry(buffer, linesize, grp, + &buffer[linesize + 1], bufsize - linesize - 1, errnop); + } while (how == nss_lt_all && !(rv & NS_TERMINATE)); +fin: + if (hes != NULL) + hesiod_free_list(ctx, hes); + if (ctx != NULL) + hesiod_end(ctx); + if (rv == NS_SUCCESS && retval != NULL) + *(struct group **)retval = grp; + return (rv); +} +#endif /* HESIOD */ + + +#ifdef YP +/* + * nis backend + */ +static void +nis_endstate(void *p) +{ + + if (p == NULL) + return; + free(((struct nis_state *)p)->key); + free(p); +} + + +static int +nis_setgrent(void *retval, void *cb_data, va_list ap) +{ + struct nis_state *st; + int rv; + + rv = nis_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + st->done = 0; + free(st->key); + st->key = NULL; + return (NS_UNAVAIL); +} + + +static int +nis_group(void *retval, void *mdata, va_list ap) +{ + char *map; + struct nis_state *st; + struct group *grp; + const char *name; + char *buffer, *key, *result; + size_t bufsize; + gid_t gid; + enum nss_lookup_type how; + int *errnop, keylen, resultlen, rv; + + name = NULL; + gid = (gid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + map = "group.byname"; + break; + case nss_lt_id: + gid = va_arg(ap, gid_t); + map = "group.bygid"; + break; + case nss_lt_all: + map = "group.byname"; + break; + } + grp = va_arg(ap, struct group *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = nis_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (st->domain[0] == '\0') { + if (getdomainname(st->domain, sizeof(st->domain)) != 0) { + *errnop = errno; + return (NS_UNAVAIL); + } + } + result = NULL; + do { + rv = NS_NOTFOUND; + switch (how) { + case nss_lt_name: + if (strlcpy(buffer, name, bufsize) >= bufsize) + goto erange; + break; + case nss_lt_id: + if (snprintf(buffer, bufsize, "%lu", + (unsigned long)gid) >= bufsize) + goto erange; + break; + case nss_lt_all: + if (st->done) + goto fin; + break; + } + result = NULL; + if (how == nss_lt_all) { + if (st->key == NULL) + rv = yp_first(st->domain, map, &st->key, + &st->keylen, &result, &resultlen); + else { + key = st->key; + keylen = st->keylen; + st->key = NULL; + rv = yp_next(st->domain, map, key, keylen, + &st->key, &st->keylen, &result, + &resultlen); + free(key); + } + if (rv != 0) { + free(result); + free(st->key); + st->key = NULL; + if (rv == YPERR_NOMORE) { + st->done = 1; + rv = NS_NOTFOUND; + } else + rv = NS_UNAVAIL; + goto fin; + } + } else { + rv = yp_match(st->domain, map, buffer, strlen(buffer), + &result, &resultlen); + if (rv == YPERR_KEY) { + rv = NS_NOTFOUND; + continue; + } else if (rv != 0) { + free(result); + rv = NS_UNAVAIL; + continue; + } + } + /* We need room at least for the line, a string NUL + * terminator, alignment padding, and one (char *) + * pointer for the member list terminator. + */ + if (resultlen >= bufsize - _ALIGNBYTES - sizeof(char *)) { + free(result); + goto erange; + } + memcpy(buffer, result, resultlen); + buffer[resultlen] = '\0'; + free(result); + rv = __gr_match_entry(buffer, resultlen, how, name, gid); + if (rv == NS_SUCCESS) + rv = __gr_parse_entry(buffer, resultlen, grp, + &buffer[resultlen+1], bufsize - resultlen - 1, + errnop); + } while (how == nss_lt_all && !(rv & NS_TERMINATE)); +fin: + if (rv == NS_SUCCESS && retval != NULL) + *(struct group **)retval = grp; + return (rv); +erange: + *errnop = ERANGE; + return (NS_RETURN); +} +#endif /* YP */ + + + +/* + * compat backend + */ +static void +compat_endstate(void *p) +{ + struct compat_state *st; + + if (p == NULL) + return; + st = (struct compat_state *)p; + free(st->name); + if (st->fp != NULL) + fclose(st->fp); + free(p); +} + + +static int +compat_setgrent(void *retval, void *mdata, va_list ap) +{ + static const ns_src compatsrc[] = { +#ifdef YP + { NSSRC_NIS, NS_SUCCESS }, +#endif + { NULL, 0 } + }; + ns_dtab dtab[] = { +#ifdef HESIOD + { NSSRC_DNS, dns_setgrent, NULL }, +#endif +#ifdef YP + { NSSRC_NIS, nis_setgrent, NULL }, +#endif + { NULL, NULL, NULL } + }; + struct compat_state *st; + int rv, stayopen; + +#define set_setent(x, y) do { \ + int i; \ + for (i = 0; i < (int)(nitems(x) - 1); i++) \ + x[i].mdata = (void *)y; \ +} while (0) + + rv = compat_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + switch ((enum constants)(uintptr_t)mdata) { + case SETGRENT: + stayopen = va_arg(ap, int); + if (st->fp != NULL) + rewind(st->fp); + else if (stayopen) + st->fp = fopen(_PATH_GROUP, "re"); + st->stayopen = stayopen; + set_setent(dtab, mdata); + (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "setgrent", + compatsrc, 0); + break; + case ENDGRENT: + if (st->fp != NULL) { + fclose(st->fp); + st->fp = NULL; + } + set_setent(dtab, mdata); + (void)_nsdispatch(NULL, dtab, NSDB_GROUP_COMPAT, "endgrent", + compatsrc, 0); + break; + default: + break; + } + st->compat = COMPAT_MODE_OFF; + free(st->name); + st->name = NULL; + return (NS_UNAVAIL); +#undef set_setent +} + + +static int +compat_group(void *retval, void *mdata, va_list ap) +{ + static const ns_src compatsrc[] = { +#ifdef YP + { NSSRC_NIS, NS_SUCCESS }, +#endif + { NULL, 0 } + }; + ns_dtab dtab[] = { +#ifdef YP + { NSSRC_NIS, nis_group, NULL }, +#endif +#ifdef HESIOD + { NSSRC_DNS, dns_group, NULL }, +#endif + { NULL, NULL, NULL } + }; + struct compat_state *st; + enum nss_lookup_type how; + const char *name, *line; + struct group *grp; + gid_t gid; + char *buffer, *p; + void *discard; + size_t bufsize, linesize; + off_t pos; + int fresh, rv, stayopen, *errnop; + +#define set_lookup_type(x, y) do { \ + int i; \ + for (i = 0; i < (int)(nitems(x) - 1); i++) \ + x[i].mdata = (void *)y; \ +} while (0) + + fresh = 0; + name = NULL; + gid = (gid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + break; + case nss_lt_id: + gid = va_arg(ap, gid_t); + break; + case nss_lt_all: + break; + default: + return (NS_NOTFOUND); + } + grp = va_arg(ap, struct group *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = compat_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (st->fp == NULL) { + st->fp = fopen(_PATH_GROUP, "re"); + if (st->fp == NULL) { + *errnop = errno; + rv = NS_UNAVAIL; + goto fin; + } + fresh = 1; + } + stayopen = (how == nss_lt_all || !fresh) ? 1 : st->stayopen; + if (stayopen) + pos = ftello(st->fp); + if (how != nss_lt_all && !fresh) + rewind(st->fp); +docompat: + switch (st->compat) { + case COMPAT_MODE_ALL: + set_lookup_type(dtab, how); + switch (how) { + case nss_lt_all: + rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, + "getgrent_r", compatsrc, grp, buffer, bufsize, + errnop); + break; + case nss_lt_id: + rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, + "getgrgid_r", compatsrc, gid, grp, buffer, bufsize, + errnop); + break; + case nss_lt_name: + rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, + "getgrnam_r", compatsrc, name, grp, buffer, + bufsize, errnop); + break; + } + if (rv & NS_TERMINATE) + goto fin; + st->compat = COMPAT_MODE_OFF; + break; + case COMPAT_MODE_NAME: + set_lookup_type(dtab, nss_lt_name); + rv = _nsdispatch(&discard, dtab, NSDB_GROUP_COMPAT, + "getgrnam_r", compatsrc, st->name, grp, buffer, bufsize, + errnop); + switch (rv) { + case NS_SUCCESS: + switch (how) { + case nss_lt_name: + if (strcmp(name, grp->gr_name) != 0) + rv = NS_NOTFOUND; + break; + case nss_lt_id: + if (gid != grp->gr_gid) + rv = NS_NOTFOUND; + break; + default: + break; + } + break; + case NS_RETURN: + goto fin; + default: + break; + } + free(st->name); + st->name = NULL; + st->compat = COMPAT_MODE_OFF; + if (rv == NS_SUCCESS) + goto fin; + break; + default: + break; + } + rv = NS_NOTFOUND; + while ((line = fgetln(st->fp, &linesize)) != NULL) { + if (line[linesize-1] == '\n') + linesize--; + if (linesize > 2 && line[0] == '+') { + p = memchr(&line[1], ':', linesize); + if (p == NULL || p == &line[1]) + st->compat = COMPAT_MODE_ALL; + else { + st->name = malloc(p - line); + if (st->name == NULL) { + syslog(LOG_ERR, + "getgrent memory allocation failure"); + *errnop = ENOMEM; + rv = NS_UNAVAIL; + break; + } + memcpy(st->name, &line[1], p - line - 1); + st->name[p - line - 1] = '\0'; + st->compat = COMPAT_MODE_NAME; + } + goto docompat; + } + rv = __gr_match_entry(line, linesize, how, name, gid); + if (rv != NS_SUCCESS) + continue; + /* We need room at least for the line, a string NUL + * terminator, alignment padding, and one (char *) + * pointer for the member list terminator. + */ + if (bufsize <= linesize + _ALIGNBYTES + sizeof(char *)) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + memcpy(buffer, line, linesize); + buffer[linesize] = '\0'; + rv = __gr_parse_entry(buffer, linesize, grp, + &buffer[linesize + 1], bufsize - linesize - 1, errnop); + if (rv & NS_TERMINATE) + break; + if (how == nss_lt_all) + pos = ftello(st->fp); + } +fin: + if (st->fp != NULL && !stayopen) { + fclose(st->fp); + st->fp = NULL; + } + if (st->fp != NULL && how != nss_lt_all) + fseeko(st->fp, pos, SEEK_SET); + if (rv == NS_SUCCESS && retval != NULL) + *(struct group **)retval = grp; + else if (rv == NS_RETURN && *errnop == ERANGE && st->fp != NULL) + fseeko(st->fp, pos, SEEK_SET); + return (rv); +#undef set_lookup_type +} + + +/* + * common group line matching and parsing + */ +int +__gr_match_entry(const char *line, size_t linesize, enum nss_lookup_type how, + const char *name, gid_t gid) +{ + size_t namesize; + const char *p, *eol; + char *q; + unsigned long n; + int i, needed; + + if (linesize == 0 || is_comment_line(line, linesize)) + return (NS_NOTFOUND); + switch (how) { + case nss_lt_name: needed = 1; break; + case nss_lt_id: needed = 2; break; + default: needed = 2; break; + } + eol = &line[linesize]; + for (p = line, i = 0; i < needed && p < eol; p++) + if (*p == ':') + i++; + if (i < needed) + return (NS_NOTFOUND); + switch (how) { + case nss_lt_name: + namesize = strlen(name); + if (namesize + 1 == (size_t)(p - line) && + memcmp(line, name, namesize) == 0) + return (NS_SUCCESS); + break; + case nss_lt_id: + n = strtoul(p, &q, 10); + if (q < eol && *q == ':' && gid == (gid_t)n) + return (NS_SUCCESS); + break; + case nss_lt_all: + return (NS_SUCCESS); + default: + break; + } + return (NS_NOTFOUND); +} + + +int +__gr_parse_entry(char *line, size_t linesize, struct group *grp, char *membuf, + size_t membufsize, int *errnop) +{ + char *s_gid, *s_mem, *p, **members; + unsigned long n; + int maxmembers; + + memset(grp, 0, sizeof(*grp)); + members = (char **)_ALIGN(membuf); + membufsize -= (char *)members - membuf; + maxmembers = membufsize / sizeof(*members); + if (maxmembers <= 0 || + (grp->gr_name = strsep(&line, ":")) == NULL || + grp->gr_name[0] == '\0' || + (grp->gr_passwd = strsep(&line, ":")) == NULL || + (s_gid = strsep(&line, ":")) == NULL || + s_gid[0] == '\0') + return (NS_NOTFOUND); + s_mem = line; + n = strtoul(s_gid, &s_gid, 10); + if (s_gid[0] != '\0') + return (NS_NOTFOUND); + grp->gr_gid = (gid_t)n; + grp->gr_mem = members; + while (maxmembers > 1 && s_mem != NULL) { + p = strsep(&s_mem, ","); + if (p != NULL && *p != '\0') { + *members++ = p; + maxmembers--; + } + } + *members = NULL; + if (s_mem == NULL) + return (NS_SUCCESS); + else { + *errnop = ERANGE; + return (NS_RETURN); + } +} + + diff --git a/lib/libc/gen/getgrouplist.3 b/lib/libc/gen/getgrouplist.3 new file mode 100644 index 000000000000..e3939fc2481a --- /dev/null +++ b/lib/libc/gen/getgrouplist.3 @@ -0,0 +1,88 @@ +.\"- +.\" SPDX-License-Identifier: BSD-3-Clause +.\" +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" Copyright (c) 2025 The FreeBSD Foundation +.\" +.\" Portions of this documentation were written by Olivier Certner +.\" <olce@FreeBSD.org> at Kumacom SARL under sponsorship from the FreeBSD +.\" Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd August 29, 2025 +.Dt GETGROUPLIST 3 +.Os +.Sh NAME +.Nm getgrouplist +.Nd produce a user's effective group list +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn getgrouplist "const char *name" "gid_t basegid" "gid_t *groups" "int *ngroups" +.Sh DESCRIPTION +The +.Fn getgrouplist +function reads through the group database to retrieve the supplementary groups +for the user specified in +.Fa name , +and returns the effective group list, whose first group is the value of +.Fa basegid +and the others are the retrieved supplementary groups. +.Fa basegid +typically is the user's group number from the password database. +.Pp +The effective group list is returned in the array pointed to by +.Fa groups . +The caller specifies the size of the +.Fa groups +array in the integer pointed to by +.Fa ngroups ; +the actual number of groups found is returned in +.Fa ngroups . +.Sh RETURN VALUES +The +.Fn getgrouplist +function +returns 0 on success and \-1 if the size of the group list is too small to +hold all the user's groups. +Here, the group array will be filled with as many groups as will fit. +.Sh FILES +.Bl -tag -width /etc/group -compact +.It Pa /etc/group +group membership list +.El +.Sh SEE ALSO +.Xr setcred 2 , +.Xr setgroups 2 , +.Xr initgroups 3 +.Sh HISTORY +The +.Fn getgrouplist +function first appeared in +.Bx 4.4 . diff --git a/lib/libc/gen/getgrouplist.c b/lib/libc/gen/getgrouplist.c new file mode 100644 index 000000000000..9c57b7031336 --- /dev/null +++ b/lib/libc/gen/getgrouplist.c @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> + +#include <unistd.h> +#include <ssp/ssp.h> + +extern int __getgroupmembership(const char *, gid_t, gid_t *, int, int *); + +int +__ssp_real(getgrouplist)(const char *uname, gid_t agroup, gid_t *groups, int *grpcnt) +{ + return __getgroupmembership(uname, agroup, groups, *grpcnt, grpcnt); +} diff --git a/lib/libc/gen/gethostname.3 b/lib/libc/gen/gethostname.3 new file mode 100644 index 000000000000..99e723fa9595 --- /dev/null +++ b/lib/libc/gen/gethostname.3 @@ -0,0 +1,128 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 13, 2020 +.Dt GETHOSTNAME 3 +.Os +.Sh NAME +.Nm gethostname , +.Nm sethostname +.Nd get/set name of current host +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn gethostname "char *name" "size_t namelen" +.Ft int +.Fn sethostname "const char *name" "int namelen" +.Sh DESCRIPTION +The +.Fn gethostname +function +returns the standard host name for the current processor, as +previously set by +.Fn sethostname . +The +.Fa namelen +argument +specifies the size of the +.Fa name +array. +The returned name is null-terminated unless insufficient space is provided. +.Pp +The +.Fn sethostname +function +sets the name of the host machine to be +.Fa name , +which has length +.Fa namelen . +This call is restricted to the super-user and +is normally used only when the system is bootstrapped. +.Pp +Applications should use +.Fn sysconf _SC_HOST_NAME_MAX +to find the maximum length of a host name (not including the terminating null). +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The following errors may be returned by these calls: +.Bl -tag -width Er +.It Bq Er EFAULT +The +.Fa name +or +.Fa namelen +argument gave an +invalid address. +.It Bq Er ENAMETOOLONG +The current host name is longer than +.Fa namelen . +(For +.Fn gethostname +only.) +.It Bq Er EPERM +The caller tried to set the host name and was not the super-user. +.El +.Sh SEE ALSO +.Xr sysconf 3 , +.Xr sysctl 3 +.Sh STANDARDS +The +.Fn gethostname +function conforms to +.St -p1003.1-2001 . +Callers should be aware that +.Brq Dv HOST_NAME_MAX +may be variable or infinite, but is guaranteed to be no less than +.Brq Dv _POSIX_HOST_NAME_MAX . +On older systems, this limit was defined in the non-standard header +.In sys/param.h +as +.Dv MAXHOSTNAMELEN , +and counted the terminating null. +The +.Fn sethostname +function and the error returns for +.Fn gethostname +are not standardized. +.Sh HISTORY +The +.Fn gethostname +function appeared in +.Bx 4.2 . +The +.Fa namelen +argument to +.Fn gethostname +was changed to +.Vt size_t +in +.Fx 5.2 +for alignment with +.St -p1003.1-2001 . diff --git a/lib/libc/gen/gethostname.c b/lib/libc/gen/gethostname.c new file mode 100644 index 000000000000..66d401fad846 --- /dev/null +++ b/lib/libc/gen/gethostname.c @@ -0,0 +1,52 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <errno.h> +#include <unistd.h> +#include <ssp/ssp.h> + +int +__ssp_real(gethostname)(char *name, size_t namelen) +{ + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + if (sysctl(mib, 2, name, &namelen, NULL, 0) == -1) { + if (errno == ENOMEM) + errno = ENAMETOOLONG; + return (-1); + } + return (0); +} diff --git a/lib/libc/gen/getloadavg.3 b/lib/libc/gen/getloadavg.3 new file mode 100644 index 000000000000..42a9f511c9ef --- /dev/null +++ b/lib/libc/gen/getloadavg.3 @@ -0,0 +1,62 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 4, 1993 +.Dt GETLOADAVG 3 +.Os +.Sh NAME +.Nm getloadavg +.Nd get system load averages +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft int +.Fn getloadavg "double loadavg[]" "int nelem" +.Sh DESCRIPTION +The +.Fn getloadavg +function returns the number of processes in the system run queue +averaged over various periods of time. +Up to +.Fa nelem +samples are retrieved and assigned to successive elements of +.Fa loadavg Ns Bq . +The system imposes a maximum of 3 samples, representing averages +over the last 1, 5, and 15 minutes, respectively. +.Sh DIAGNOSTICS +If the load average was unobtainable, \-1 is returned; otherwise, +the number of samples actually retrieved is returned. +.Sh SEE ALSO +.Xr uptime 1 , +.Xr kvm_getloadavg 3 , +.Xr sysctl 3 +.Sh HISTORY +The +.Fn getloadavg +function appeared in +.Bx 4.3 Reno . diff --git a/lib/libc/gen/getloadavg.c b/lib/libc/gen/getloadavg.c new file mode 100644 index 000000000000..4f6c23627f0e --- /dev/null +++ b/lib/libc/gen/getloadavg.c @@ -0,0 +1,63 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <sys/sysctl.h> +#include <vm/vm_param.h> + +#include <stdlib.h> + +/* + * getloadavg() -- Get system load averages. + * + * Put `nelem' samples into `loadavg' array. + * Return number of samples retrieved, or -1 on error. + */ +int +getloadavg(double loadavg[], int nelem) +{ + struct loadavg loadinfo; + int i, mib[2]; + size_t size; + + mib[0] = CTL_VM; + mib[1] = VM_LOADAVG; + size = sizeof(loadinfo); + if (sysctl(mib, 2, &loadinfo, &size, NULL, 0) < 0) + return (-1); + + nelem = MIN(nelem, sizeof(loadinfo.ldavg) / sizeof(fixpt_t)); + for (i = 0; i < nelem; i++) + loadavg[i] = (double) loadinfo.ldavg[i] / loadinfo.fscale; + return (nelem); +} diff --git a/lib/libc/gen/getlogin.c b/lib/libc/gen/getlogin.c new file mode 100644 index 000000000000..f8a3fb079067 --- /dev/null +++ b/lib/libc/gen/getlogin.c @@ -0,0 +1,84 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <errno.h> +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "namespace.h" +#include <pthread.h> +#include <ssp/ssp.h> +#include "un-namespace.h" + +#include "libc_private.h" + +extern int _getlogin(char *, int); + +char * +getlogin(void) +{ + static char logname[MAXLOGNAME]; + + if (_getlogin(logname, sizeof(logname)) < 0) + return (NULL); + return (logname[0] != '\0' ? logname : NULL); +} + +int +__ssp_real(getlogin_r)(char *logname, size_t namelen) +{ + char tmpname[MAXLOGNAME]; + int len; + + if (namelen < 1) + return (ERANGE); + logname[0] = '\0'; + + if (_getlogin(tmpname, sizeof(tmpname)) < 0) + return (errno); + len = strlen(tmpname) + 1; + if (len > namelen) + return (ERANGE); + strlcpy(logname, tmpname, len); + return (0); +} + +/* FreeBSD 12 and earlier compat. */ +int +__getlogin_r_fbsd12(char *logname, int namelen) +{ + if (namelen < 1) + return (ERANGE); + return (getlogin_r(logname, namelen)); +} +__sym_compat(getlogin_r, __getlogin_r_fbsd12, FBSD_1.0); diff --git a/lib/libc/gen/getmntinfo-compat11.c b/lib/libc/gen/getmntinfo-compat11.c new file mode 100644 index 000000000000..d5c308b387a0 --- /dev/null +++ b/lib/libc/gen/getmntinfo-compat11.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/ucred.h> +#define _WANT_FREEBSD11_STATFS +#include <sys/mount.h> +#include <stdlib.h> +#include "gen-compat.h" + +/* + * Return information about mounted filesystems. + */ +int +freebsd11_getmntinfo(struct freebsd11_statfs **mntbufp, int flags) +{ + static struct freebsd11_statfs *mntbuf; + static int mntsize; + static long bufsize; + + if (mntsize <= 0 && + (mntsize = freebsd11_getfsstat(0, 0, MNT_NOWAIT)) < 0) + return (0); + if (bufsize > 0 && + (mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0) + return (0); + while (bufsize <= mntsize * sizeof(struct freebsd11_statfs)) { + if (mntbuf) + free(mntbuf); + bufsize = (mntsize + 1) * sizeof(struct freebsd11_statfs); + if ((mntbuf = (struct freebsd11_statfs *)malloc(bufsize)) == 0) + return (0); + if ((mntsize = freebsd11_getfsstat(mntbuf, bufsize, flags)) < 0) + return (0); + } + *mntbufp = mntbuf; + return (mntsize); +} + +__sym_compat(getmntinfo, freebsd11_getmntinfo, FBSD_1.0); diff --git a/lib/libc/gen/getmntinfo.3 b/lib/libc/gen/getmntinfo.3 new file mode 100644 index 000000000000..2bbe436078d6 --- /dev/null +++ b/lib/libc/gen/getmntinfo.3 @@ -0,0 +1,106 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd December 27, 2016 +.Dt GETMNTINFO 3 +.Os +.Sh NAME +.Nm getmntinfo +.Nd get information about mounted file systems +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/param.h +.In sys/ucred.h +.In sys/mount.h +.Ft int +.Fn getmntinfo "struct statfs **mntbufp" "int mode" +.Sh DESCRIPTION +The +.Fn getmntinfo +function +returns an array of +.Fn statfs +structures describing each currently mounted file system (see +.Xr statfs 2 ) . +.Pp +The +.Fn getmntinfo +function +passes its +.Fa mode +argument transparently to +.Xr getfsstat 2 . +.Sh RETURN VALUES +On successful completion, +.Fn getmntinfo +returns a count of the number of elements in the array. +The pointer to the array is stored into +.Fa mntbufp . +.Pp +If an error occurs, zero is returned and the external variable +.Va errno +is set to indicate the error. +Although the pointer +.Fa mntbufp +will be unmodified, any information previously returned by +.Fn getmntinfo +will be lost. +.Sh ERRORS +The +.Fn getmntinfo +function +may fail and set errno for any of the errors specified for the library +routines +.Xr getfsstat 2 +or +.Xr malloc 3 . +.Sh SEE ALSO +.Xr getfsstat 2 , +.Xr mount 2 , +.Xr statfs 2 , +.Xr mount 8 +.Sh HISTORY +The +.Fn getmntinfo +function first appeared in +.Bx 4.4 . +.Sh BUGS +The +.Fn getmntinfo +function writes the array of structures to an internal static object +and returns +a pointer to that object. +Subsequent calls to +.Fn getmntinfo +will modify the same object. +.Pp +The memory allocated by +.Fn getmntinfo +cannot be +.Xr free 3 Ns 'd +by the application. diff --git a/lib/libc/gen/getmntinfo.c b/lib/libc/gen/getmntinfo.c new file mode 100644 index 000000000000..3c224ef27d76 --- /dev/null +++ b/lib/libc/gen/getmntinfo.c @@ -0,0 +1,66 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/ucred.h> +#include <sys/mount.h> +#include <stdlib.h> + +#define MAX_TRIES 3 +#define SCALING_FACTOR 2 + +/* + * Return information about mounted filesystems. + */ +int +getmntinfo(struct statfs **mntbufp, int mode) +{ + static struct statfs *mntbuf; + static int mntsize; + static long bufsize; + unsigned tries = 0; + + if (mntsize <= 0 && (mntsize = getfsstat(0, 0, MNT_NOWAIT)) < 0) + return (0); + if (bufsize > 0 && (mntsize = getfsstat(mntbuf, bufsize, mode)) < 0) + return (0); + while (tries++ < MAX_TRIES && bufsize <= mntsize * sizeof(*mntbuf)) { + bufsize = (mntsize * SCALING_FACTOR) * sizeof(*mntbuf); + if ((mntbuf = reallocf(mntbuf, bufsize)) == NULL) + return (0); + if ((mntsize = getfsstat(mntbuf, bufsize, mode)) < 0) + return (0); + } + *mntbufp = mntbuf; + if (mntsize > (bufsize / sizeof(*mntbuf))) + return (bufsize / sizeof(*mntbuf)); + return (mntsize); +} diff --git a/lib/libc/gen/getnetgrent.3 b/lib/libc/gen/getnetgrent.3 new file mode 100644 index 000000000000..be2e3cd1cdd5 --- /dev/null +++ b/lib/libc/gen/getnetgrent.3 @@ -0,0 +1,130 @@ +.\" Copyright (c) 1992, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 5, 2016 +.Dt GETNETGRENT 3 +.Os +.Sh NAME +.Nm getnetgrent , +.Nm innetgr , +.Nm setnetgrent , +.Nm endnetgrent +.Nd netgroup database operations +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In netdb.h +.Ft int +.Fn getnetgrent "char **host" "char **user" "char **domain" +.Ft int +.Fn getnetgrent_r "char **host" "char **user" "char **domain" "char *buf" "size_t bufsize" +.Ft int +.Fn innetgr "const char *netgroup" "const char *host" "const char *user" "const char *domain" +.Ft void +.Fn setnetgrent "const char *netgroup" +.Ft void +.Fn endnetgrent void +.Sh DESCRIPTION +These functions operate on the netgroup database file +.Pa /etc/netgroup +which is described +in +.Xr netgroup 5 . +The database defines a set of netgroups, each made up of one or more triples: +.Bd -literal -offset indent +(host, user, domain) +.Ed +that defines a combination of host, user and domain. +Any of the three fields may be specified as ``wildcards'' that match any +string. +.Pp +The function +.Fn getnetgrent +sets the three pointer arguments to the strings of the next member of the +current netgroup. +If any of the string pointers are +.Dv NULL +that field is considered a wildcard. +.Pp +The functions +.Fn setnetgrent +and +.Fn endnetgrent +set the current netgroup and terminate the current netgroup respectively. +If +.Fn setnetgrent +is called with a different netgroup than the previous call, an implicit +.Fn endnetgrent +is implied. +The +.Fn setnetgrent +function +also sets the offset to the first member of the netgroup. +.Pp +The function +.Fn innetgr +searches for a match of all fields within the specified group. +If any of the +.Sy host , +.Sy user , +or +.Sy domain +arguments are +.Dv NULL +those fields will match any string value in the netgroup member. +.Sh RETURN VALUES +The function +.Fn getnetgrent +returns 0 for ``no more netgroup members'' and 1 otherwise. +The function +.Fn innetgr +returns 1 for a successful match and 0 otherwise. +The functions +.Fn setnetgrent +and +.Fn endnetgrent +have no return value. +.Sh FILES +.Bl -tag -width /etc/netgroup -compact +.It Pa /etc/netgroup +netgroup database file +.El +.Sh COMPATIBILITY +The netgroup members have three string fields to maintain compatibility +with other vendor implementations, however it is not obvious what use the +.Sy domain +string has within +.Bx . +.Sh SEE ALSO +.Xr netgroup 5 +.Sh BUGS +The function +.Fn getnetgrent +returns pointers to dynamically allocated data areas that are freed when +the function +.Fn endnetgrent +is called. diff --git a/lib/libc/gen/getnetgrent.c b/lib/libc/gen/getnetgrent.c new file mode 100644 index 000000000000..7c92bc2ce9a9 --- /dev/null +++ b/lib/libc/gen/getnetgrent.c @@ -0,0 +1,1012 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Rick Macklem at The University of Guelph. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" + +#include <ctype.h> +#include <errno.h> +#include <netdb.h> +#include <nsswitch.h> +#include <pthread.h> +#include <pthread_np.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "nss_tls.h" + +#ifdef YP +/* + * Notes: + * We want to be able to use NIS netgroups properly while retaining + * the ability to use a local /etc/netgroup file. Unfortunately, you + * can't really do both at the same time - at least, not efficiently. + * NetBSD deals with this problem by creating a netgroup database + * using Berkeley DB (just like the password database) that allows + * for lookups using netgroup, netgroup.byuser or netgroup.byhost + * searches. This is a neat idea, but I don't have time to implement + * something like that now. (I think ultimately it would be nice + * if we DB-fied the group and netgroup stuff all in one shot, but + * for now I'm satisfied just to have something that works well + * without requiring massive code changes.) + * + * Therefore, to still permit the use of the local file and maintain + * optimum NIS performance, we allow for the following conditions: + * + * - If /etc/netgroup does not exist and NIS is turned on, we use + * NIS netgroups only. + * + * - If /etc/netgroup exists but is empty, we use NIS netgroups + * only. + * + * - If /etc/netgroup exists and contains _only_ a '+', we use + * NIS netgroups only. + * + * - If /etc/netgroup exists, contains locally defined netgroups + * and a '+', we use a mixture of NIS and the local entries. + * This method should return the same NIS data as just using + * NIS alone, but it will be slower if the NIS netgroup database + * is large (innetgr() in particular will suffer since extra + * processing has to be done in order to determine memberships + * using just the raw netgroup data). + * + * - If /etc/netgroup exists and contains only locally defined + * netgroup entries, we use just those local entries and ignore + * NIS (this is the original, pre-NIS behavior). + */ + +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/errno.h> +static char *_netgr_yp_domain; +int _use_only_yp; +static int _netgr_yp_enabled; +static int _yp_innetgr; +#endif + +#ifndef _PATH_NETGROUP +#define _PATH_NETGROUP "/etc/netgroup" +#endif + +enum constants { + NGRP_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ + NGRP_STORAGE_MAX = 1 << 20, /* 1 MByte */ +}; + +static const ns_src defaultsrc[] = { + { NSSRC_COMPAT, NS_SUCCESS }, + { NULL, 0 }, +}; + +/* + * Static Variables and functions used by setnetgrent(), getnetgrent() and + * endnetgrent(). + * There are two linked lists: + * - linelist is just used by setnetgrent() to parse the net group file via. + * parse_netgrp() + * - netgrp is the list of entries for the current netgroup + */ +struct linelist { + struct linelist *l_next; /* Chain ptr. */ + int l_parsed; /* Flag for cycles */ + char *l_groupname; /* Name of netgroup */ + char *l_line; /* Netgroup entrie(s) to be parsed */ +}; + +struct netgrp { + struct netgrp *ng_next; /* Chain ptr */ + char *ng_str[3]; /* Field pointers, see below */ +}; + +struct netgr_state { + FILE *st_netf; + struct linelist *st_linehead; + struct netgrp *st_nextgrp; + struct netgrp *st_gr; + char *st_grname; +}; + +#define NG_HOST 0 /* Host name */ +#define NG_USER 1 /* User name */ +#define NG_DOM 2 /* and Domain name */ + +static void netgr_endstate(void *); +NSS_TLS_HANDLING(netgr); + +static int files_endnetgrent(void *, void *, va_list); +static int files_getnetgrent_r(void *, void *, va_list); +static int files_setnetgrent(void *, void *, va_list); + +static int compat_endnetgrent(void *, void *, va_list); +static int compat_innetgr(void *, void *, va_list); +static int compat_getnetgrent_r(void *, void *, va_list); +static int compat_setnetgrent(void *, void *, va_list); + +static void _compat_clearstate(void); +static int _getnetgrent_r(char **, char **, char **, char *, size_t, int *, + struct netgr_state *); +static int _innetgr_fallback(void *, void *, const char *, const char *, + const char *, const char *); +static int innetgr_fallback(void *, void *, va_list); +static int parse_netgrp(const char *, struct netgr_state *, int); +static struct linelist *read_for_group(const char *, struct netgr_state *, int); + +#define LINSIZ 1024 /* Length of netgroup file line */ + +static const ns_dtab getnetgrent_dtab[] = { + NS_FILES_CB(files_getnetgrent_r, NULL) + NS_COMPAT_CB(compat_getnetgrent_r, NULL) + { NULL, NULL, NULL }, +}; + +static const ns_dtab setnetgrent_dtab[] = { + NS_FILES_CB(files_setnetgrent, NULL) + NS_COMPAT_CB(compat_setnetgrent, NULL) + { NULL, NULL, NULL }, +}; + +static const ns_dtab endnetgrent_dtab[] = { + NS_FILES_CB(files_endnetgrent, NULL) + NS_COMPAT_CB(compat_endnetgrent, NULL) + { NULL, NULL, NULL }, +}; + +static struct netgr_state compat_state; + +static void +netgr_endstate(void *arg) +{ + struct linelist *lp, *olp; + struct netgrp *gp, *ogp; + struct netgr_state *st; + + st = (struct netgr_state *)arg; + lp = st->st_linehead; + while (lp != NULL) { + olp = lp; + lp = lp->l_next; + free(olp->l_groupname); + free(olp->l_line); + free(olp); + } + st->st_linehead = NULL; + if (st->st_grname != NULL) { + free(st->st_grname); + st->st_grname = NULL; + } + gp = st->st_gr; + while (gp != NULL) { + ogp = gp; + gp = gp->ng_next; + free(ogp->ng_str[NG_HOST]); + free(ogp->ng_str[NG_USER]); + free(ogp->ng_str[NG_DOM]); + free(ogp); + } + st->st_gr = NULL; + st->st_nextgrp = NULL; +} + +static int +files_getnetgrent_r(void *retval, void *mdata, va_list ap) +{ + struct netgr_state *st; + char **hostp, **userp, **domp, *buf; + size_t bufsize; + int *errnop; + + hostp = va_arg(ap, char **); + userp = va_arg(ap, char **); + domp = va_arg(ap, char **); + buf = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + + if (netgr_getstate(&st) != 0) + return (NS_UNAVAIL); + + return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop, st)); +} + +static int +files_setnetgrent(void *retval, void *mdata, va_list ap) +{ + const ns_src src[] = { + { NSSRC_FILES, NS_SUCCESS }, + { NULL, 0 }, + }; + struct netgr_state *st; + const char *group; + int rv; + + group = va_arg(ap, const char *); + + if (group == NULL || group[0] == '\0') + return (NS_RETURN); + + rv = netgr_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + + if (st->st_gr == NULL || strcmp(group, st->st_grname) != 0) { + (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, + "endnetgrent", src); + if ((st->st_netf = fopen(_PATH_NETGROUP, "re")) != NULL) { + if (parse_netgrp(group, st, 0) != 0) + (void)_nsdispatch(NULL, endnetgrent_dtab, + NSDB_NETGROUP, "endnetgrent", src); + else + st->st_grname = strdup(group); + (void)fclose(st->st_netf); + st->st_netf = NULL; + } + } + st->st_nextgrp = st->st_gr; + return (st->st_grname != NULL ? NS_SUCCESS : NS_NOTFOUND); +} + +static int +files_endnetgrent(void *retval, void *mdata, va_list ap) +{ + struct netgr_state *st; + + if (netgr_getstate(&st) != 0) + return (NS_UNAVAIL); + netgr_endstate(st); + return (NS_SUCCESS); +} + +static int +compat_getnetgrent_r(void *retval, void *mdata, va_list ap) +{ + char **hostp, **userp, **domp, *buf; + size_t bufsize; + int *errnop; +#ifdef YP + _yp_innetgr = 0; +#endif + + hostp = va_arg(ap, char **); + userp = va_arg(ap, char **); + domp = va_arg(ap, char **); + buf = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + + return (_getnetgrent_r(hostp, userp, domp, buf, bufsize, errnop, + &compat_state)); +} + +/* + * compat_setnetgrent() + * Parse the netgroup file looking for the netgroup and build the list + * of netgrp structures. Let parse_netgrp() and read_for_group() do + * most of the work. + */ +static int +compat_setnetgrent(void *retval, void *mdata, va_list ap) +{ + FILE *netf; + const char *group; +#ifdef YP + struct stat _yp_statp; + char _yp_plus; +#endif + + group = va_arg(ap, const char *); + + /* Sanity check */ + if (group == NULL || !strlen(group)) + return (NS_RETURN); + + if (compat_state.st_gr == NULL || + strcmp(group, compat_state.st_grname) != 0) { + _compat_clearstate(); + +#ifdef YP + /* Presumed guilty until proven innocent. */ + _use_only_yp = 0; + /* + * If /etc/netgroup doesn't exist or is empty, + * use NIS exclusively. + */ + if (((stat(_PATH_NETGROUP, &_yp_statp) < 0) && + errno == ENOENT) || _yp_statp.st_size == 0) + _use_only_yp = _netgr_yp_enabled = 1; + if ((netf = fopen(_PATH_NETGROUP,"re")) != NULL ||_use_only_yp){ + compat_state.st_netf = netf; + /* + * Icky: grab the first character of the netgroup file + * and turn on NIS if it's a '+'. rewind the stream + * afterwards so we don't goof up read_for_group() later. + */ + if (netf) { + fscanf(netf, "%c", &_yp_plus); + rewind(netf); + if (_yp_plus == '+') + _use_only_yp = _netgr_yp_enabled = 1; + } + /* + * If we were called specifically for an innetgr() + * lookup and we're in NIS-only mode, short-circuit + * parse_netgroup() and cut directly to the chase. + */ + if (_use_only_yp && _yp_innetgr) { + /* dohw! */ + if (netf != NULL) + fclose(netf); + return (NS_RETURN); + } +#else + if ((netf = fopen(_PATH_NETGROUP, "re"))) { + compat_state.st_netf = netf; +#endif + if (parse_netgrp(group, &compat_state, 1)) { + _compat_clearstate(); + } else { + compat_state.st_grname = strdup(group); + } + if (netf) + fclose(netf); + } + } + compat_state.st_nextgrp = compat_state.st_gr; + return (NS_SUCCESS); +} + +static void +_compat_clearstate(void) +{ + +#ifdef YP + _netgr_yp_enabled = 0; +#endif + netgr_endstate(&compat_state); +} + +/* + * compat_endnetgrent() - cleanup + */ +static int +compat_endnetgrent(void *retval, void *mdata, va_list ap) +{ + + _compat_clearstate(); + return (NS_SUCCESS); +} + +int +_getnetgrent_r(char **hostp, char **userp, char **domp, char *buf, + size_t bufsize, int *errnop, struct netgr_state *st) +{ + char *p, *src; + size_t len; + int rv; + +#define COPY_NG_ELEM(dstp, i) do { \ + src = st->st_nextgrp->ng_str[(i)]; \ + if (src == NULL) \ + src = ""; \ + len = strlcpy(p, src, bufsize); \ + if (len >= bufsize) { \ + *errnop = ERANGE; \ + return (NS_RETURN); \ + } \ + *(dstp) = p; \ + p += len + 1; \ + bufsize -= len + 1; \ +} while (0) + + p = buf; + if (st->st_nextgrp != NULL) { + COPY_NG_ELEM(hostp, NG_HOST); + COPY_NG_ELEM(userp, NG_USER); + COPY_NG_ELEM(domp, NG_DOM); + st->st_nextgrp = st->st_nextgrp->ng_next; + rv = NS_SUCCESS; + } else { + rv = NS_NOTFOUND; + } +#undef COPY_NG_ELEM + + return (rv); +} + +#ifdef YP +static int +_listmatch(const char *list, const char *group, int len) +{ + const char *ptr = list; + const char *cptr; + int glen = strlen(group); + + /* skip possible leading whitespace */ + while (isspace((unsigned char)*ptr)) + ptr++; + + while (ptr < list + len) { + cptr = ptr; + while(*ptr != ',' && *ptr != '\0' && !isspace((unsigned char)*ptr)) + ptr++; + if (strncmp(cptr, group, glen) == 0 && glen == (ptr - cptr)) + return (1); + while (*ptr == ',' || isspace((unsigned char)*ptr)) + ptr++; + } + + return (0); +} + +static int +_revnetgr_lookup(char* lookupdom, char* map, const char* str, + const char* dom, const char* group) +{ + int y, rv, rot; + char key[MAXHOSTNAMELEN]; + char *result; + int resultlen; + + for (rot = 0; ; rot++) { + switch (rot) { + case 0: + snprintf(key, MAXHOSTNAMELEN, "%s.%s", str, + dom ? dom : lookupdom); + break; + case 1: + snprintf(key, MAXHOSTNAMELEN, "%s.*", str); + break; + case 2: + snprintf(key, MAXHOSTNAMELEN, "*.%s", + dom ? dom : lookupdom); + break; + case 3: + snprintf(key, MAXHOSTNAMELEN, "*.*"); + break; + default: + return (0); + } + y = yp_match(lookupdom, map, key, strlen(key), &result, + &resultlen); + if (y == 0) { + rv = _listmatch(result, group, resultlen); + free(result); + if (rv) + return (1); + } else if (y != YPERR_KEY) { + /* + * If we get an error other than 'no + * such key in map' then something is + * wrong and we should stop the search. + */ + return (-1); + } + } +} +#endif + +/* + * Search for a match in a netgroup. + */ +static int +compat_innetgr(void *retval, void *mdata, va_list ap) +{ +#ifdef YP + const ns_src src[] = { + { mdata, NS_SUCCESS }, + { NULL, 0 }, + }; +#endif + const char *group, *host, *user, *dom; + + group = va_arg(ap, const char *); + host = va_arg(ap, const char *); + user = va_arg(ap, const char *); + dom = va_arg(ap, const char *); + + if (group == NULL || !strlen(group)) + return (NS_RETURN); + +#ifdef YP + _yp_innetgr = 1; + (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent", + src, group); + _yp_innetgr = 0; + /* + * If we're in NIS-only mode, do the search using + * NIS 'reverse netgroup' lookups. + * + * What happens with 'reverse netgroup' lookups: + * + * 1) try 'reverse netgroup' lookup + * 1.a) if host is specified and user is null: + * look in netgroup.byhost + * (try host.domain, host.*, *.domain or *.*) + * if found, return yes + * 1.b) if user is specified and host is null: + * look in netgroup.byuser + * (try host.domain, host.*, *.domain or *.*) + * if found, return yes + * 1.c) if both host and user are specified, + * don't do 'reverse netgroup' lookup. It won't work. + * 1.d) if neither host ane user are specified (why?!?) + * don't do 'reverse netgroup' lookup either. + * 2) if domain is specified and 'reverse lookup' is done: + * 'reverse lookup' was authoritative. bye bye. + * 3) otherwise, too bad, try it the slow way. + */ + if (_use_only_yp && (host == NULL) != (user == NULL)) { + int ret; + if(yp_get_default_domain(&_netgr_yp_domain)) + return (NS_NOTFOUND); + ret = _revnetgr_lookup(_netgr_yp_domain, + host?"netgroup.byhost":"netgroup.byuser", + host?host:user, dom, group); + if (ret == 1) { + *(int *)retval = 1; + return (NS_SUCCESS); + } else if (ret == 0 && dom != NULL) { + *(int *)retval = 0; + return (NS_SUCCESS); + } + } +#endif /* YP */ + + return (_innetgr_fallback(retval, mdata, group, host, user, dom)); +} + +static int +_innetgr_fallback(void *retval, void *mdata, const char *group, const char *host, + const char *user, const char *dom) +{ + const ns_src src[] = { + { mdata, NS_SUCCESS }, + { NULL, 0 }, + }; + char *h, *u, *d; + char *buf; + size_t bufsize; + int rv, ret_errno; + + if (group == NULL || group[0] == '\0') + return (NS_RETURN); + + bufsize = NGRP_STORAGE_INITIAL; + buf = malloc(bufsize); + if (buf == NULL) + return (NS_UNAVAIL); + + *(int *)retval = 0; + + (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent", + src, group); + + for (;;) { + do { + ret_errno = 0; + rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, + "getnetgrent_r", src, &h, &u, &d, buf, bufsize, + &ret_errno); + if (rv != NS_SUCCESS && ret_errno == ERANGE) { + bufsize *= 2; + if (bufsize > NGRP_STORAGE_MAX || + (buf = reallocf(buf, bufsize)) == NULL) + goto out; + } + } while (rv != NS_SUCCESS && ret_errno == ERANGE); + + if (rv != NS_SUCCESS) { + if (rv == NS_NOTFOUND && ret_errno == 0) + rv = NS_SUCCESS; + break; + } + + if ((host == NULL || h == NULL || strcmp(host, h) == 0) && + (user == NULL || u == NULL || strcmp(user, u) == 0) && + (dom == NULL || d == NULL || strcmp(dom, d) == 0)) { + *(int *)retval = 1; + break; + } + } + +out: + free(buf); + (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent", + src); + return (rv); +} + +static int +innetgr_fallback(void *retval, void *mdata, va_list ap) +{ + const char *group, *host, *user, *dom; + + group = va_arg(ap, const char *); + host = va_arg(ap, const char *); + user = va_arg(ap, const char *); + dom = va_arg(ap, const char *); + + return (_innetgr_fallback(retval, mdata, group, host, user, dom)); +} + +/* + * Parse the netgroup file setting up the linked lists. + */ +static int +parse_netgrp(const char *group, struct netgr_state *st, int niscompat) +{ + struct netgrp *grp; + struct linelist *lp = st->st_linehead; + char **ng; + char *epos, *gpos, *pos, *spos; + int freepos, len, strpos; +#ifdef DEBUG + int fields; +#endif + + /* + * First, see if the line has already been read in. + */ + while (lp) { + if (!strcmp(group, lp->l_groupname)) + break; + lp = lp->l_next; + } + if (lp == NULL && (lp = read_for_group(group, st, niscompat)) == NULL) + return (1); + if (lp->l_parsed) { +#ifdef DEBUG + /* + * This error message is largely superflous since the + * code handles the error condition sucessfully, and + * spewing it out from inside libc can actually hose + * certain programs. + */ + fprintf(stderr, "Cycle in netgroup %s\n", lp->l_groupname); +#endif + return (1); + } else + lp->l_parsed = 1; + pos = lp->l_line; + /* Watch for null pointer dereferences, dammit! */ + while (pos != NULL && *pos != '\0') { + if (*pos == '(') { + grp = malloc(sizeof(*grp)); + if (grp == NULL) + return (1); + ng = grp->ng_str; + bzero(grp, sizeof(*grp)); + pos++; + gpos = strsep(&pos, ")"); +#ifdef DEBUG + fields = 0; +#endif + for (strpos = 0; strpos < 3; strpos++) { + if ((spos = strsep(&gpos, ",")) == NULL) { + /* + * All other systems I've tested + * return NULL for empty netgroup + * fields. It's up to user programs + * to handle the NULLs appropriately. + */ + ng[strpos] = NULL; + continue; + } +#ifdef DEBUG + fields++; +#endif + while (*spos == ' ' || *spos == '\t') + spos++; + if ((epos = strpbrk(spos, " \t"))) { + *epos = '\0'; + len = epos - spos; + } else + len = strlen(spos); + if (len <= 0) + continue; + ng[strpos] = malloc(len + 1); + if (ng[strpos] == NULL) { + for (freepos = 0; freepos < strpos; + freepos++) + free(ng[freepos]); + free(grp); + return (1); + } + bcopy(spos, ng[strpos], len + 1); + } + grp->ng_next = st->st_gr; + st->st_gr = grp; +#ifdef DEBUG + /* + * Note: on other platforms, malformed netgroup + * entries are not normally flagged. While we + * can catch bad entries and report them, we should + * stay silent by default for compatibility's sake. + */ + if (fields < 3) { + fprintf(stderr, + "Bad entry (%s%s%s%s%s) in netgroup \"%s\"\n", + ng[NG_HOST] == NULL ? "" : ng[NG_HOST], + ng[NG_USER] == NULL ? "" : ",", + ng[NG_USER] == NULL ? "" : ng[NG_USER], + ng[NG_DOM] == NULL ? "" : ",", + ng[NG_DOM] == NULL ? "" : ng[NG_DOM], + lp->l_groupname); + } +#endif + } else { + spos = strsep(&pos, ", \t"); + if (parse_netgrp(spos, st, niscompat)) + continue; + } + if (pos == NULL) + break; + while (*pos == ' ' || *pos == ',' || *pos == '\t') + pos++; + } + return (0); +} + +/* + * Read the netgroup file and save lines until the line for the netgroup + * is found. Return 1 if eof is encountered. + */ +static struct linelist * +read_for_group(const char *group, struct netgr_state *st, int niscompat) +{ + char *linep, *olinep, *pos, *spos; + int len, olen; + int cont; + struct linelist *lp; + char line[LINSIZ + 2]; + FILE *netf; +#ifdef YP + char *result; + int resultlen; + linep = NULL; + + netf = st->st_netf; + while ((_netgr_yp_enabled && niscompat) || + fgets(line, LINSIZ, netf) != NULL) { + if (_netgr_yp_enabled) { + if(!_netgr_yp_domain) + if(yp_get_default_domain(&_netgr_yp_domain)) + continue; + if (yp_match(_netgr_yp_domain, "netgroup", group, + strlen(group), &result, &resultlen)) { + free(result); + if (_use_only_yp) + return ((struct linelist *)0); + else { + _netgr_yp_enabled = 0; + continue; + } + } + if (strlen(result) == 0) { + free(result); + return (NULL); + } + snprintf(line, LINSIZ, "%s %s", group, result); + free(result); + } +#else + linep = NULL; + while (fgets(line, LINSIZ, netf) != NULL) { +#endif + pos = (char *)&line; +#ifdef YP + if (niscompat && *pos == '+') { + _netgr_yp_enabled = 1; + continue; + } +#endif + if (*pos == '#') + continue; + while (*pos == ' ' || *pos == '\t') + pos++; + spos = pos; + while (*pos != ' ' && *pos != '\t' && *pos != '\n' && + *pos != '\0') + pos++; + len = pos - spos; + while (*pos == ' ' || *pos == '\t') + pos++; + if (*pos != '\n' && *pos != '\0') { + lp = malloc(sizeof (*lp)); + if (lp == NULL) + return (NULL); + lp->l_parsed = 0; + lp->l_groupname = malloc(len + 1); + if (lp->l_groupname == NULL) { + free(lp); + return (NULL); + } + bcopy(spos, lp->l_groupname, len); + *(lp->l_groupname + len) = '\0'; + len = strlen(pos); + olen = 0; + + /* + * Loop around handling line continuations. + */ + do { + if (*(pos + len - 1) == '\n') + len--; + if (*(pos + len - 1) == '\\') { + len--; + cont = 1; + } else + cont = 0; + if (len > 0) { + linep = malloc(olen + len + 1); + if (linep == NULL) { + free(lp->l_groupname); + free(lp); + if (olen > 0) + free(olinep); + return (NULL); + } + if (olen > 0) { + bcopy(olinep, linep, olen); + free(olinep); + } + bcopy(pos, linep + olen, len); + olen += len; + *(linep + olen) = '\0'; + olinep = linep; + } + if (cont) { + if (fgets(line, LINSIZ, netf)) { + pos = line; + len = strlen(pos); + } else + cont = 0; + } + } while (cont); + lp->l_line = linep; + lp->l_next = st->st_linehead; + st->st_linehead = lp; + + /* + * If this is the one we wanted, we are done. + */ + if (!strcmp(lp->l_groupname, group)) + return (lp); + } + } +#ifdef YP + /* + * Yucky. The recursive nature of this whole mess might require + * us to make more than one pass through the netgroup file. + * This might be best left outside the #ifdef YP, but YP is + * defined by default anyway, so I'll leave it like this + * until I know better. + */ + rewind(netf); +#endif + return (NULL); +} + +int +getnetgrent_r(char **hostp, char **userp, char **domp, char *buf, size_t bufsize) +{ + int rv, ret_errno; + + ret_errno = 0; + rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, "getnetgrent_r", + defaultsrc, hostp, userp, domp, buf, bufsize, &ret_errno); + if (rv == NS_SUCCESS) { + return (1); + } else { + errno = ret_errno; + return (0); + } +} + +int +getnetgrent(char **hostp, char **userp, char **domp) +{ + static char *ngrp_storage; + static size_t ngrp_storage_size; + int ret_errno, rv; + + if (ngrp_storage == NULL) { + ngrp_storage_size = NGRP_STORAGE_INITIAL; + ngrp_storage = malloc(ngrp_storage_size); + if (ngrp_storage == NULL) + return (0); + } + + do { + ret_errno = 0; + rv = _nsdispatch(NULL, getnetgrent_dtab, NSDB_NETGROUP, + "getnetgrent_r", defaultsrc, hostp, userp, domp, + ngrp_storage, ngrp_storage_size, &ret_errno); + if (rv != NS_SUCCESS && ret_errno == ERANGE) { + ngrp_storage_size *= 2; + if (ngrp_storage_size > NGRP_STORAGE_MAX) { + free(ngrp_storage); + ngrp_storage = NULL; + errno = ERANGE; + return (0); + } + ngrp_storage = reallocf(ngrp_storage, + ngrp_storage_size); + if (ngrp_storage == NULL) + return (0); + } + } while (rv != NS_SUCCESS && ret_errno == ERANGE); + + if (rv == NS_SUCCESS) { + return (1); + } else { + errno = ret_errno; + return (0); + } +} + +void +setnetgrent(const char *netgroup) +{ + + (void)_nsdispatch(NULL, setnetgrent_dtab, NSDB_NETGROUP, "setnetgrent", + defaultsrc, netgroup); +} + +void +endnetgrent(void) +{ + + (void)_nsdispatch(NULL, endnetgrent_dtab, NSDB_NETGROUP, "endnetgrent", + defaultsrc); +} + +int +innetgr(const char *netgroup, const char *host, const char *user, + const char *domain) +{ + static const ns_dtab dtab[] = { + NS_COMPAT_CB(compat_innetgr, NULL) + NS_FALLBACK_CB(innetgr_fallback) + { NULL, NULL, NULL }, + }; + int result, rv; + + rv = _nsdispatch(&result, dtab, NSDB_NETGROUP, "innetgr", defaultsrc, + netgroup, host, user, domain); + return (rv == NS_SUCCESS ? result : 0); +} diff --git a/lib/libc/gen/getosreldate.3 b/lib/libc/gen/getosreldate.3 new file mode 100644 index 000000000000..6ce5a11d131c --- /dev/null +++ b/lib/libc/gen/getosreldate.3 @@ -0,0 +1,83 @@ +.\" Copyright (c) 2002 The FreeBSD Project. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 13, 2018 +.Dt GETOSRELDATE 3 +.Os +.Sh NAME +.Nm getosreldate +.Nd get the value of +.Dv __FreeBSD_version +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn getosreldate void +.Sh DESCRIPTION +The +.Fn getosreldate +function returns an integer showing the version of the +currently running +.Fx +kernel. +Definitions of the values can be found in +.%B "The Porter's Handbook": +.Pp +.Lk https://www.FreeBSD.org/doc/en/books/porters-handbook/ +.Sh RETURN VALUES +Upon successful completion, +.Fn getosreldate +returns the value requested; +otherwise the value \-1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ENVIRONMENT +.Bl -tag -width ".Ev OSVERSION" +.It Ev OSVERSION +If the environment variable +.Ev OSVERSION +is set, it will override the +.Fn getosreldate +return value. +.El +.Sh EXAMPLES +An example can be found in +.Pa /usr/share/examples/FreeBSD_version . +.Sh ERRORS +The +.Fn getosreldate +function may fail and set +.Va errno +for any of the errors specified for the library function +.Xr sysctl 3 . +.Sh SEE ALSO +.Rs +.%B "The Porter's Handbook" +.Re +.Sh HISTORY +The +.Fn getosreldate +function appeared in +.Fx 2.0 . diff --git a/lib/libc/gen/getosreldate.c b/lib/libc/gen/getosreldate.c new file mode 100644 index 000000000000..edd978973ade --- /dev/null +++ b/lib/libc/gen/getosreldate.c @@ -0,0 +1,57 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/sysctl.h> + +#include <stdlib.h> +#include <unistd.h> + +int +getosreldate(void) +{ + int mib[2]; + size_t size; + int value; + char *temp; + + if ((temp = getenv("OSVERSION"))) { + value = atoi(temp); + return (value); + } + + mib[0] = CTL_KERN; + mib[1] = KERN_OSRELDATE; + size = sizeof value; + if (sysctl(mib, 2, &value, &size, NULL, 0) == -1) + return (-1); + return (value); +} diff --git a/lib/libc/gen/getpass.3 b/lib/libc/gen/getpass.3 new file mode 100644 index 000000000000..c88e072e1900 --- /dev/null +++ b/lib/libc/gen/getpass.3 @@ -0,0 +1,90 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 4, 1993 +.Dt GETPASS 3 +.Os +.Sh NAME +.Nm getpass +.Nd get a password +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In pwd.h +.In unistd.h +.Ft char * +.Fn getpass "const char *prompt" +.Sh DESCRIPTION +The +.Fn getpass +function displays a prompt to, and reads in a password from, +.Pa /dev/tty . +If this file is not accessible, +.Fn getpass +displays the prompt on the standard error output and reads from the standard +input. +.Pp +The password may be up to _PASSWORD_LEN (currently 128) +characters in length. +Any additional +characters and the terminating newline character are discarded. +.Pp +The +.Fn getpass +function turns off character echoing while reading the password. +.Sh RETURN VALUES +The +.Fn getpass +function returns a pointer to the null terminated password. +.Sh FILES +.Bl -tag -width /dev/tty -compact +.It Pa /dev/tty +.El +.Sh SEE ALSO +.Xr crypt 3 , +.Xr readpassphrase 3 +.Sh HISTORY +A +.Fn getpass +function appeared in +.At v7 . +.Sh BUGS +The +.Fn getpass +function leaves its result in an internal static object and returns +a pointer to that object. +Subsequent calls to +.Fn getpass +will modify the same object. +.Pp +The calling process should zero the password as soon as possible to +avoid leaving the cleartext password visible in the process's address +space. +.Pp +Upon receipt of a SIGTSTP, the input buffer will be flushed, so any +partially typed password must be retyped when the process +continues. diff --git a/lib/libc/gen/getpeereid.3 b/lib/libc/gen/getpeereid.3 new file mode 100644 index 000000000000..8e3b763f716a --- /dev/null +++ b/lib/libc/gen/getpeereid.3 @@ -0,0 +1,134 @@ +.\" +.\" Copyright (c) 2001 Dima Dorfman. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 16, 2023 +.Dt GETPEEREID 3 +.Os +.Sh NAME +.Nm getpeereid +.Nd get the effective credentials of a UNIX-domain peer +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn getpeereid "int s" "uid_t *euid" "gid_t *egid" +.Sh DESCRIPTION +The +.Fn getpeereid +function returns the effective user and group IDs of the +peer connected to a +.Ux Ns -domain +socket. +The argument +.Fa s +must be a connected +.Ux Ns -domain +socket +.Pq Xr unix 4 +of type +.Dv SOCK_STREAM +on which either +.Xr connect 2 +or +.Xr listen 2 +has been called. +The effective user ID is placed in +.Fa euid , +and the effective group ID in +.Fa egid . +.Pp +The credentials returned to the +.Xr listen 2 +caller are those of its peer at the time it called +.Xr connect 2 ; +the credentials returned to the +.Xr connect 2 +caller are those of its peer at the time it called +.Xr listen 2 . +This mechanism is reliable; there is no way for either side to influence +the credentials returned to its peer except by calling the appropriate +system call (i.e., either +.Xr connect 2 +or +.Xr listen 2 ) +under different effective credentials. +.Pp +One common use of this routine is for a +.Ux Ns -domain +server +to verify the credentials of its client. +Likewise, the client can verify the credentials of the server. +.Sh IMPLEMENTATION NOTES +On +.Fx , +.Fn getpeereid +is implemented in terms of the +.Dv LOCAL_PEERCRED +.Xr unix 4 +socket option. +.Sh RETURN VALUES +.Rv -std getpeereid +.Sh ERRORS +The +.Fn getpeereid +function +fails if: +.Bl -tag -width Er +.It Bq Er EBADF +The argument +.Fa s +is not a valid descriptor. +.It Bq Er ENOTSOCK +The argument +.Fa s +is a file, not a socket. +.It Bq Er ENOTCONN +The argument +.Fa s +does not refer to a socket on which +.Xr connect 2 +or +.Xr listen 2 +have been called. +.It Bq Er EINVAL +The argument +.Fa s +does not refer to a socket of type +.Dv SOCK_STREAM , +or the kernel returned invalid data. +.El +.Sh SEE ALSO +.Xr connect 2 , +.Xr getpeername 2 , +.Xr getsockname 2 , +.Xr getsockopt 2 , +.Xr listen 2 , +.Xr unix 4 +.Sh HISTORY +The +.Fn getpeereid +function appeared in +.Fx 4.6 . diff --git a/lib/libc/gen/getpeereid.c b/lib/libc/gen/getpeereid.c new file mode 100644 index 000000000000..444dd2664cc4 --- /dev/null +++ b/lib/libc/gen/getpeereid.c @@ -0,0 +1,57 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2001 Dima Dorfman. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/ucred.h> +#include <sys/un.h> + +#include <errno.h> +#include <unistd.h> +#include "un-namespace.h" + +int +getpeereid(int s, uid_t *euid, gid_t *egid) +{ + struct xucred xuc; + socklen_t xuclen; + int error; + + xuclen = sizeof(xuc); + error = _getsockopt(s, SOL_LOCAL, LOCAL_PEERCRED, &xuc, &xuclen); + if (error != 0) + return (error); + if (xuc.cr_version != XUCRED_VERSION) { + errno = EINVAL; + return (-1); + } + *euid = xuc.cr_uid; + *egid = xuc.cr_gid; + return (0); +} diff --git a/lib/libc/gen/getprogname.3 b/lib/libc/gen/getprogname.3 new file mode 100644 index 000000000000..7bc2c50d79c4 --- /dev/null +++ b/lib/libc/gen/getprogname.3 @@ -0,0 +1,118 @@ +.\" +.\" Copyright (c) 2001 Christopher G. Demetriou +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgement: +.\" This product includes software developed for the +.\" NetBSD Project. See http://www.netbsd.org/ for +.\" information about NetBSD. +.\" 4. The name of the author may not be used to endorse or promote products +.\" derived from this software without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 18, 2021 +.Dt GETPROGNAME 3 +.Os +.Sh NAME +.Nm getprogname , +.Nm setprogname +.Nd get or set the program name +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft const char * +.Fn getprogname "void" +.Ft void +.Fn setprogname "const char *progname" +.Sh DESCRIPTION +The +.Fn getprogname +and +.Fn setprogname +functions manipulate the name of the current program. +They are used by error-reporting routines to produce +consistent output. +.Pp +The +.Fn getprogname +function returns the name of the program. +If the name has not been set yet, it will return +.Dv NULL . +.Pp +The +.Fn setprogname +function sets the name of the program to be the last component of the +.Fa progname +argument. +Since a pointer to the given string is kept as the program name, +it should not be modified for the rest of the program's lifetime. +.Pp +In +.Fx , +the name of the program is set by the start-up code that is run before +.Fn main ; +thus, +running +.Fn setprogname +is not necessary. +Programs that desire maximum portability should still call it; +on another operating system, +these functions may be implemented in a portability library. +Calling +.Fn setprogname +allows the aforementioned library to learn the program name without +modifications to the start-up code. +.Sh EXAMPLES +The following example presents a simple program, which shows the difference +between +.Fn getprogname +and +.Va "argv[0]" . +.Bd -literal -offset indent +#include <stdio.h> +#include <stdlib.h> + +int +main(int argc, char** argv) +{ + printf("getprogname(): %s\en", getprogname()); + printf("argv[0]: %s\en", argv[0]); + return (0); +} +.Ed +.Pp +When compiled and executed (e.g., with +.Ql ./a.out ) +the output of the program is going to look like this: +.Bd -literal -offset indent +getprogname(): a.out +argv[0]: ./a.out +.Ed +.Sh SEE ALSO +.Xr err 3 , +.Xr setproctitle 3 +.Sh HISTORY +These functions first appeared in +.Nx 1.6 , +and made their way into +.Fx 4.4 . diff --git a/lib/libc/gen/getprogname.c b/lib/libc/gen/getprogname.c new file mode 100644 index 000000000000..54e59b6ac412 --- /dev/null +++ b/lib/libc/gen/getprogname.c @@ -0,0 +1,14 @@ +#include "namespace.h" +#include <stdlib.h> +#include "un-namespace.h" + +#include "libc_private.h" + +__weak_reference(_getprogname, getprogname); + +const char * +_getprogname(void) +{ + + return (__progname); +} diff --git a/lib/libc/gen/getpwent.3 b/lib/libc/gen/getpwent.3 new file mode 100644 index 000000000000..486f0cab2399 --- /dev/null +++ b/lib/libc/gen/getpwent.3 @@ -0,0 +1,311 @@ +.\" Copyright (c) 1988, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 28, 2022 +.Dt GETPWENT 3 +.Os +.Sh NAME +.Nm getpwent , +.Nm getpwent_r , +.Nm getpwnam , +.Nm getpwnam_r , +.Nm getpwuid , +.Nm getpwuid_r , +.Nm setpassent , +.Nm setpwent , +.Nm endpwent +.Nd password database operations +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In pwd.h +.Ft struct passwd * +.Fn getpwent void +.Ft int +.Fn getpwent_r "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result" +.Ft struct passwd * +.Fn getpwnam "const char *login" +.Ft int +.Fn getpwnam_r "const char *name" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result" +.Ft struct passwd * +.Fn getpwuid "uid_t uid" +.Ft int +.Fn getpwuid_r "uid_t uid" "struct passwd *pwd" "char *buffer" "size_t bufsize" "struct passwd **result" +.Ft int +.Fn setpassent "int stayopen" +.Ft void +.Fn setpwent void +.Ft void +.Fn endpwent void +.Sh DESCRIPTION +These functions +operate on the password database file +which is described +in +.Xr passwd 5 . +Each entry in the database is defined by the structure +.Vt passwd +found in the include +file +.In pwd.h : +.Bd -literal -offset indent +struct passwd { + char *pw_name; /* user name */ + char *pw_passwd; /* encrypted password */ + uid_t pw_uid; /* user uid */ + gid_t pw_gid; /* user gid */ + time_t pw_change; /* password change time */ + char *pw_class; /* user access class */ + char *pw_gecos; /* Honeywell login info */ + char *pw_dir; /* home directory */ + char *pw_shell; /* default shell */ + time_t pw_expire; /* account expiration */ + int pw_fields; /* internal: fields filled in */ +}; +.Ed +.Pp +The functions +.Fn getpwnam +and +.Fn getpwuid +search the password database for the given login name or user uid, +respectively, always returning the first one encountered. +.Pp +The +.Fn getpwent +function +sequentially reads the password database and is intended for programs +that wish to process the complete list of users. +.Pp +The functions +.Fn getpwent_r , +.Fn getpwnam_r , +and +.Fn getpwuid_r +are thread-safe versions of +.Fn getpwent , +.Fn getpwnam , +and +.Fn getpwuid , +respectively. +The caller must provide storage for the results of the search in +the +.Fa pwd , +.Fa buffer , +.Fa bufsize , +and +.Fa result +arguments. +When these functions are successful, the +.Fa pwd +argument will be filled-in, and a pointer to that argument will be +stored in +.Fa result . +If an entry is not found or an error occurs, +.Fa result +will be set to +.Dv NULL . +.Pp +The +.Fn setpassent +function +accomplishes two purposes. +First, it causes +.Fn getpwent +to ``rewind'' to the beginning of the database. +Additionally, if +.Fa stayopen +is non-zero, file descriptors are left open, significantly speeding +up subsequent accesses for all of the routines. +(This latter functionality is unnecessary for +.Fn getpwent +as it does not close its file descriptors by default.) +.Pp +It is dangerous for long-running programs to keep the file descriptors +open as the database will become out of date if it is updated while the +program is running. +.Pp +The +.Fn setpwent +function +is identical to +.Fn setpassent +with an argument of zero. +.Pp +The +.Fn endpwent +function +closes any open files. +.Pp +These routines have been written to ``shadow'' the password file, e.g.\& +allow only certain programs to have access to the encrypted password. +If the process which calls them has an effective uid of 0, the encrypted +password will be returned, otherwise, the password field of the returned +structure will point to the string +.Ql * . +.Sh RETURN VALUES +The functions +.Fn getpwent , +.Fn getpwnam , +and +.Fn getpwuid +return a valid pointer to a passwd structure on success +or +.Dv NULL +if the entry is not found or if an error occurs. +If an error does occur, +.Va errno +will be set. +Note that programs must explicitly set +.Va errno +to zero before calling any of these functions if they need to +distinguish between a non-existent entry and an error. +The functions +.Fn getpwent_r , +.Fn getpwnam_r , +and +.Fn getpwuid_r +return 0 if no error occurred, or an error number to indicate failure. +It is not an error if a matching entry is not found. +(Thus, if +.Fa result +is +.Dv NULL +and the return value is 0, no matching entry exists.) +.Pp +The +.Fn setpassent +function returns 0 on failure and 1 on success. +The +.Fn endpwent +and +.Fn setpwent +functions +have no return value. +.Sh FILES +.Bl -tag -width /etc/master.passwd -compact +.It Pa /etc/pwd.db +The insecure password database file +.It Pa /etc/spwd.db +The secure password database file +.It Pa /etc/master.passwd +The current password file +.It Pa /etc/passwd +A Version 7 format password file +.El +.Sh COMPATIBILITY +The historic function +.Xr setpwfile 3 , +which allowed the specification of alternate password databases, +has been deprecated and is no longer available. +.Sh ERRORS +These routines may fail for any of the errors specified in +.Xr open 2 , +.Xr dbopen 3 , +.Xr socket 2 , +and +.Xr connect 2 , +in addition to the following: +.Bl -tag -width Er +.It Bq Er ERANGE +The buffer specified by the +.Fa buffer +and +.Fa bufsize +arguments was insufficiently sized to store the result. +The caller should retry with a larger buffer. +.El +.Sh SEE ALSO +.Xr getlogin 2 , +.Xr getgrent 3 , +.Xr nsswitch.conf 5 , +.Xr passwd 5 , +.Xr pwd_mkdb 8 , +.Xr vipw 8 , +.Xr yp 8 +.Sh STANDARDS +The +.Fn getpwent , +.Fn getpwnam , +.Fn getpwnam_r , +.Fn getpwuid , +.Fn getpwuid_r , +.Fn setpwent , +and +.Fn endpwent +functions conform to +.St -p1003.1-96 . +.Sh HISTORY +The +.Fn getpwent , +.Fn getpwnam , +.Fn getpwuid , +.Fn setpwent , +and +.Fn endpwent +functions appeared in +.At v7 . +The +.Fn setpassent +function appeared in +.Bx 4.3 Reno . +The +.Fn getpwent_r , +.Fn getpwnam_r , +and +.Fn getpwuid_r +functions appeared in +.Fx 5.1 . +.Sh BUGS +The functions +.Fn getpwent , +.Fn getpwnam , +and +.Fn getpwuid , +leave their results in an internal static object and return +a pointer to that object. +Subsequent calls to +the same function +will modify the same object. +.Pp +The functions +.Fn getpwent , +.Fn getpwent_r , +.Fn endpwent , +.Fn setpassent , +and +.Fn setpwent +are fairly useless in a networked environment and should be +avoided, if possible. +The +.Fn getpwent +and +.Fn getpwent_r +functions +make no attempt to suppress duplicate information if multiple +sources are specified in +.Xr nsswitch.conf 5 . diff --git a/lib/libc/gen/getpwent.c b/lib/libc/gen/getpwent.c new file mode 100644 index 000000000000..1cbf97e7eb52 --- /dev/null +++ b/lib/libc/gen/getpwent.c @@ -0,0 +1,2001 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2003 Networks Associates Technology, Inc. + * All rights reserved. + * + * This software was developed for the FreeBSD Project by + * Jacques A. Vidrine, Safeport Network Services, and Network + * Associates Laboratories, the Security Research Division of Network + * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 + * ("CBOSS"), as part of the DARPA CHATS research program. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#include "namespace.h" +#include <sys/param.h> +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/yp_prot.h> +#include <rpcsvc/ypclnt.h> +#endif +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#ifdef HESIOD +#include <hesiod.h> +#endif +#include <netdb.h> +#include <nsswitch.h> +#include <pthread.h> +#include <pthread_np.h> +#include <pwd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h> +#include "un-namespace.h" +#include <db.h> +#include "libc_private.h" +#include "pw_scan.h" +#include "nss_tls.h" +#ifdef NS_CACHING +#include "nscache.h" +#endif + +#ifndef CTASSERT +#define CTASSERT(x) _CTASSERT(x, __LINE__) +#define _CTASSERT(x, y) __CTASSERT(x, y) +#define __CTASSERT(x, y) typedef char __assert_ ## y [(x) ? 1 : -1] +#endif + +/* Counter as stored in /etc/pwd.db */ +typedef int pwkeynum; + +CTASSERT(MAXLOGNAME > sizeof(uid_t)); +CTASSERT(MAXLOGNAME > sizeof(pwkeynum)); + +enum constants { + PWD_STORAGE_INITIAL = 1 << 10, /* 1 KByte */ + PWD_STORAGE_MAX = 1 << 20, /* 1 MByte */ + SETPWENT = 1, + ENDPWENT = 2, + HESIOD_NAME_MAX = 256 +}; + +static const ns_src defaultsrc[] = { + { NSSRC_COMPAT, NS_SUCCESS }, + { NULL, 0 } +}; + +int __pw_match_entry(const char *, size_t, enum nss_lookup_type, + const char *, uid_t); +int __pw_parse_entry(char *, size_t, struct passwd *, int, int *errnop); + +union key { + const char *name; + uid_t uid; +}; + +static struct passwd *getpw(int (*fn)(union key, struct passwd *, char *, + size_t, struct passwd **), union key); +static int wrap_getpwnam_r(union key, struct passwd *, char *, + size_t, struct passwd **); +static int wrap_getpwuid_r(union key, struct passwd *, char *, size_t, + struct passwd **); +static int wrap_getpwent_r(union key, struct passwd *, char *, size_t, + struct passwd **); + +static int pwdb_match_entry_v3(char *, size_t, enum nss_lookup_type, + const char *, uid_t); +static int pwdb_parse_entry_v3(char *, size_t, struct passwd *, int *); +static int pwdb_match_entry_v4(char *, size_t, enum nss_lookup_type, + const char *, uid_t); +static int pwdb_parse_entry_v4(char *, size_t, struct passwd *, int *); + + +struct { + int (*match)(char *, size_t, enum nss_lookup_type, const char *, + uid_t); + int (*parse)(char *, size_t, struct passwd *, int *); +} pwdb_versions[] = { + { NULL, NULL }, /* version 0 */ + { NULL, NULL }, /* version 1 */ + { NULL, NULL }, /* version 2 */ + { pwdb_match_entry_v3, pwdb_parse_entry_v3 }, /* version 3 */ + { pwdb_match_entry_v4, pwdb_parse_entry_v4 }, /* version 4 */ +}; + + +struct files_state { + DB *db; + pwkeynum keynum; + int stayopen; + int version; +}; +static void files_endstate(void *); +NSS_TLS_HANDLING(files); +static DB *pwdbopen(int *); +static void files_endstate(void *); +static int files_setpwent(void *, void *, va_list); +static int files_passwd(void *, void *, va_list); + + +#ifdef HESIOD +struct dns_state { + long counter; +}; +static void dns_endstate(void *); +NSS_TLS_HANDLING(dns); +static int dns_setpwent(void *, void *, va_list); +static int dns_passwd(void *, void *, va_list); +#endif + + +#ifdef YP +struct nis_state { + char domain[MAXHOSTNAMELEN]; + int done; + char *key; + int keylen; +}; +static void nis_endstate(void *); +NSS_TLS_HANDLING(nis); +static int nis_setpwent(void *, void *, va_list); +static int nis_passwd(void *, void *, va_list); +static int nis_map(char *, enum nss_lookup_type, char *, size_t, int *); +static int nis_adjunct(char *, const char *, char *, size_t); +#endif + + +struct compat_state { + DB *db; + pwkeynum keynum; + int stayopen; + int version; + DB *exclude; + struct passwd template; + char *name; + enum _compat { + COMPAT_MODE_OFF = 0, + COMPAT_MODE_ALL, + COMPAT_MODE_NAME, + COMPAT_MODE_NETGROUP + } compat; +}; +static void compat_endstate(void *); +NSS_TLS_HANDLING(compat); +static int compat_setpwent(void *, void *, va_list); +static int compat_passwd(void *, void *, va_list); +static void compat_clear_template(struct passwd *); +static int compat_set_template(struct passwd *, struct passwd *); +static int compat_use_template(struct passwd *, struct passwd *, char *, + size_t); +static int compat_redispatch(struct compat_state *, enum nss_lookup_type, + enum nss_lookup_type, const char *, const char *, uid_t, + struct passwd *, char *, size_t, int *); + +#ifdef NS_CACHING +static int pwd_id_func(char *, size_t *, va_list ap, void *); +static int pwd_marshal_func(char *, size_t *, void *, va_list, void *); +static int pwd_unmarshal_func(char *, size_t, void *, va_list, void *); + +static int +pwd_id_func(char *buffer, size_t *buffer_size, va_list ap, void *cache_mdata) +{ + char *name; + uid_t uid; + size_t size, desired_size; + int res = NS_UNAVAIL; + enum nss_lookup_type lookup_type; + + lookup_type = (enum nss_lookup_type)(uintptr_t)cache_mdata; + switch (lookup_type) { + case nss_lt_name: + name = va_arg(ap, char *); + size = strlen(name); + desired_size = sizeof(enum nss_lookup_type) + size + 1; + if (desired_size > *buffer_size) { + res = NS_RETURN; + goto fin; + } + + memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); + memcpy(buffer + sizeof(enum nss_lookup_type), name, size + 1); + + res = NS_SUCCESS; + break; + case nss_lt_id: + uid = va_arg(ap, uid_t); + desired_size = sizeof(enum nss_lookup_type) + sizeof(uid_t); + if (desired_size > *buffer_size) { + res = NS_RETURN; + goto fin; + } + + memcpy(buffer, &lookup_type, sizeof(enum nss_lookup_type)); + memcpy(buffer + sizeof(enum nss_lookup_type), &uid, + sizeof(uid_t)); + + res = NS_SUCCESS; + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + +fin: + *buffer_size = desired_size; + return (res); +} + +static int +pwd_marshal_func(char *buffer, size_t *buffer_size, void *retval, va_list ap, + void *cache_mdata) +{ + char *name __unused; + uid_t uid __unused; + struct passwd *pwd; + char *orig_buf __unused; + size_t orig_buf_size __unused; + + struct passwd new_pwd; + size_t desired_size, size; + char *p; + + switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + uid = va_arg(ap, uid_t); + break; + case nss_lt_all: + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + + pwd = va_arg(ap, struct passwd *); + orig_buf = va_arg(ap, char *); + orig_buf_size = va_arg(ap, size_t); + + desired_size = sizeof(struct passwd) + sizeof(char *) + + strlen(pwd->pw_name) + 1; + if (pwd->pw_passwd != NULL) + desired_size += strlen(pwd->pw_passwd) + 1; + if (pwd->pw_class != NULL) + desired_size += strlen(pwd->pw_class) + 1; + if (pwd->pw_gecos != NULL) + desired_size += strlen(pwd->pw_gecos) + 1; + if (pwd->pw_dir != NULL) + desired_size += strlen(pwd->pw_dir) + 1; + if (pwd->pw_shell != NULL) + desired_size += strlen(pwd->pw_shell) + 1; + + if (*buffer_size < desired_size) { + /* this assignment is here for future use */ + *buffer_size = desired_size; + return (NS_RETURN); + } + + memcpy(&new_pwd, pwd, sizeof(struct passwd)); + memset(buffer, 0, desired_size); + + *buffer_size = desired_size; + p = buffer + sizeof(struct passwd) + sizeof(char *); + memcpy(buffer + sizeof(struct passwd), &p, sizeof(char *)); + + if (new_pwd.pw_name != NULL) { + size = strlen(new_pwd.pw_name); + memcpy(p, new_pwd.pw_name, size); + new_pwd.pw_name = p; + p += size + 1; + } + + if (new_pwd.pw_passwd != NULL) { + size = strlen(new_pwd.pw_passwd); + memcpy(p, new_pwd.pw_passwd, size); + new_pwd.pw_passwd = p; + p += size + 1; + } + + if (new_pwd.pw_class != NULL) { + size = strlen(new_pwd.pw_class); + memcpy(p, new_pwd.pw_class, size); + new_pwd.pw_class = p; + p += size + 1; + } + + if (new_pwd.pw_gecos != NULL) { + size = strlen(new_pwd.pw_gecos); + memcpy(p, new_pwd.pw_gecos, size); + new_pwd.pw_gecos = p; + p += size + 1; + } + + if (new_pwd.pw_dir != NULL) { + size = strlen(new_pwd.pw_dir); + memcpy(p, new_pwd.pw_dir, size); + new_pwd.pw_dir = p; + p += size + 1; + } + + if (new_pwd.pw_shell != NULL) { + size = strlen(new_pwd.pw_shell); + memcpy(p, new_pwd.pw_shell, size); + new_pwd.pw_shell = p; + p += size + 1; + } + + memcpy(buffer, &new_pwd, sizeof(struct passwd)); + return (NS_SUCCESS); +} + +static int +pwd_unmarshal_func(char *buffer, size_t buffer_size, void *retval, va_list ap, + void *cache_mdata) +{ + char *name __unused; + uid_t uid __unused; + struct passwd *pwd; + char *orig_buf; + size_t orig_buf_size; + int *ret_errno; + + char *p; + + switch ((enum nss_lookup_type)(uintptr_t)cache_mdata) { + case nss_lt_name: + name = va_arg(ap, char *); + break; + case nss_lt_id: + uid = va_arg(ap, uid_t); + break; + case nss_lt_all: + break; + default: + /* should be unreachable */ + return (NS_UNAVAIL); + } + + pwd = va_arg(ap, struct passwd *); + orig_buf = va_arg(ap, char *); + orig_buf_size = va_arg(ap, size_t); + ret_errno = va_arg(ap, int *); + + if (orig_buf_size + sizeof(struct passwd) + sizeof(char *) < + buffer_size) { + *ret_errno = ERANGE; + return (NS_RETURN); + } else if (buffer_size < sizeof(struct passwd) + sizeof(char *)) { + /* + * nscd(8) sometimes returns buffer_size=1 for nonexistent + * entries. + */ + *ret_errno = 0; + return (NS_NOTFOUND); + } + + memcpy(pwd, buffer, sizeof(struct passwd)); + memcpy(&p, buffer + sizeof(struct passwd), sizeof(char *)); + memcpy(orig_buf, buffer + sizeof(struct passwd) + sizeof(char *), + buffer_size - sizeof(struct passwd) - sizeof(char *)); + + NS_APPLY_OFFSET(pwd->pw_name, orig_buf, p, char *); + NS_APPLY_OFFSET(pwd->pw_passwd, orig_buf, p, char *); + NS_APPLY_OFFSET(pwd->pw_class, orig_buf, p, char *); + NS_APPLY_OFFSET(pwd->pw_gecos, orig_buf, p, char *); + NS_APPLY_OFFSET(pwd->pw_dir, orig_buf, p, char *); + NS_APPLY_OFFSET(pwd->pw_shell, orig_buf, p, char *); + + if (retval != NULL) + *((struct passwd **)retval) = pwd; + + return (NS_SUCCESS); +} + +NSS_MP_CACHE_HANDLING(passwd); +#endif /* NS_CACHING */ + +void +setpwent(void) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( + passwd, (void *)nss_lt_all, + NULL, NULL); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_setpwent, (void *)SETPWENT }, +#ifdef HESIOD + { NSSRC_DNS, dns_setpwent, (void *)SETPWENT }, +#endif +#ifdef YP + { NSSRC_NIS, nis_setpwent, (void *)SETPWENT }, +#endif + { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, 0); +} + + +int +setpassent(int stayopen) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( + passwd, (void *)nss_lt_all, + NULL, NULL); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_setpwent, (void *)SETPWENT }, +#ifdef HESIOD + { NSSRC_DNS, dns_setpwent, (void *)SETPWENT }, +#endif +#ifdef YP + { NSSRC_NIS, nis_setpwent, (void *)SETPWENT }, +#endif + { NSSRC_COMPAT, compat_setpwent, (void *)SETPWENT }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "setpwent", defaultsrc, + stayopen); + return (1); +} + + +void +endpwent(void) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( + passwd, (void *)nss_lt_all, + NULL, NULL); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_setpwent, (void *)ENDPWENT }, +#ifdef HESIOD + { NSSRC_DNS, dns_setpwent, (void *)ENDPWENT }, +#endif +#ifdef YP + { NSSRC_NIS, nis_setpwent, (void *)ENDPWENT }, +#endif + { NSSRC_COMPAT, compat_setpwent, (void *)ENDPWENT }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + (void)_nsdispatch(NULL, dtab, NSDB_PASSWD, "endpwent", defaultsrc); +} + + +int +getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize, + struct passwd **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = NS_MP_CACHE_INFO_INITIALIZER( + passwd, (void *)nss_lt_all, + pwd_marshal_func, pwd_unmarshal_func); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_passwd, (void *)nss_lt_all }, +#ifdef HESIOD + { NSSRC_DNS, dns_passwd, (void *)nss_lt_all }, +#endif +#ifdef YP + { NSSRC_NIS, nis_passwd, (void *)nss_lt_all }, +#endif + { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_all }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + __pw_initpwd(pwd); + ret_errno = 0; + *result = NULL; + rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwent_r", defaultsrc, + pwd, buffer, bufsize, &ret_errno); + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + + +int +getpwnam_r(const char *name, struct passwd *pwd, char *buffer, size_t bufsize, + struct passwd **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = + NS_COMMON_CACHE_INFO_INITIALIZER( + passwd, (void *)nss_lt_name, + pwd_id_func, pwd_marshal_func, pwd_unmarshal_func); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_passwd, (void *)nss_lt_name }, +#ifdef HESIOD + { NSSRC_DNS, dns_passwd, (void *)nss_lt_name }, +#endif +#ifdef YP + { NSSRC_NIS, nis_passwd, (void *)nss_lt_name }, +#endif + { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_name }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + __pw_initpwd(pwd); + ret_errno = 0; + *result = NULL; + rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwnam_r", defaultsrc, + name, pwd, buffer, bufsize, &ret_errno); + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + + +int +getpwuid_r(uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, + struct passwd **result) +{ +#ifdef NS_CACHING + static const nss_cache_info cache_info = + NS_COMMON_CACHE_INFO_INITIALIZER( + passwd, (void *)nss_lt_id, + pwd_id_func, pwd_marshal_func, pwd_unmarshal_func); +#endif + + static const ns_dtab dtab[] = { + { NSSRC_FILES, files_passwd, (void *)nss_lt_id }, +#ifdef HESIOD + { NSSRC_DNS, dns_passwd, (void *)nss_lt_id }, +#endif +#ifdef YP + { NSSRC_NIS, nis_passwd, (void *)nss_lt_id }, +#endif + { NSSRC_COMPAT, compat_passwd, (void *)nss_lt_id }, +#ifdef NS_CACHING + NS_CACHE_CB(&cache_info) +#endif + { NULL, NULL, NULL } + }; + int rv, ret_errno; + + __pw_initpwd(pwd); + ret_errno = 0; + *result = NULL; + rv = _nsdispatch(result, dtab, NSDB_PASSWD, "getpwuid_r", defaultsrc, + uid, pwd, buffer, bufsize, &ret_errno); + if (rv == NS_SUCCESS) + return (0); + else + return (ret_errno); +} + + +static struct passwd pwd; +static char *pwd_storage; +static size_t pwd_storage_size; + + +static struct passwd * +getpw(int (*fn)(union key, struct passwd *, char *, size_t, struct passwd **), + union key key) +{ + int rv; + struct passwd *res; + + if (pwd_storage == NULL) { + pwd_storage = malloc(PWD_STORAGE_INITIAL); + if (pwd_storage == NULL) + return (NULL); + pwd_storage_size = PWD_STORAGE_INITIAL; + } + do { + rv = fn(key, &pwd, pwd_storage, pwd_storage_size, &res); + if (res == NULL && rv == ERANGE) { + free(pwd_storage); + if ((pwd_storage_size << 1) > PWD_STORAGE_MAX) { + pwd_storage = NULL; + errno = ERANGE; + return (NULL); + } + pwd_storage_size <<= 1; + pwd_storage = malloc(pwd_storage_size); + if (pwd_storage == NULL) + return (NULL); + } + } while (res == NULL && rv == ERANGE); + if (rv != 0) + errno = rv; + return (res); +} + + +static int +wrap_getpwnam_r(union key key, struct passwd *pwd, char *buffer, + size_t bufsize, struct passwd **res) +{ + return (getpwnam_r(key.name, pwd, buffer, bufsize, res)); +} + + +static int +wrap_getpwuid_r(union key key, struct passwd *pwd, char *buffer, + size_t bufsize, struct passwd **res) +{ + return (getpwuid_r(key.uid, pwd, buffer, bufsize, res)); +} + + +static int +wrap_getpwent_r(union key key __unused, struct passwd *pwd, char *buffer, + size_t bufsize, struct passwd **res) +{ + return (getpwent_r(pwd, buffer, bufsize, res)); +} + + +struct passwd * +getpwnam(const char *name) +{ + union key key; + + key.name = name; + return (getpw(wrap_getpwnam_r, key)); +} + + +struct passwd * +getpwuid(uid_t uid) +{ + union key key; + + key.uid = uid; + return (getpw(wrap_getpwuid_r, key)); +} + + +struct passwd * +getpwent(void) +{ + union key key; + + key.uid = 0; /* not used */ + return (getpw(wrap_getpwent_r, key)); +} + + +/* + * files backend + */ +static DB * +pwdbopen(int *version) +{ + DB *res; + DBT key, entry; + int rv; + + if (geteuid() != 0 || + (res = dbopen(_PATH_SMP_DB, O_RDONLY, 0, DB_HASH, NULL)) == NULL) + res = dbopen(_PATH_MP_DB, O_RDONLY, 0, DB_HASH, NULL); + if (res == NULL) + return (NULL); + key.data = _PWD_VERSION_KEY; + key.size = strlen(_PWD_VERSION_KEY); + rv = res->get(res, &key, &entry, 0); + if (rv == 0) + *version = *(unsigned char *)entry.data; + else + *version = 3; + if (*version < 3 || + *version >= nitems(pwdb_versions)) { + syslog(LOG_CRIT, "Unsupported password database version %d", + *version); + res->close(res); + res = NULL; + } + return (res); +} + + +static void +files_endstate(void *p) +{ + DB *db; + + if (p == NULL) + return; + db = ((struct files_state *)p)->db; + if (db != NULL) + db->close(db); + free(p); +} + + +static int +files_setpwent(void *retval, void *mdata, va_list ap) +{ + struct files_state *st; + int rv, stayopen; + + rv = files_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + switch ((enum constants)(uintptr_t)mdata) { + case SETPWENT: + stayopen = va_arg(ap, int); + st->keynum = 0; + if (stayopen) + st->db = pwdbopen(&st->version); + st->stayopen = stayopen; + break; + case ENDPWENT: + if (st->db != NULL) { + (void)st->db->close(st->db); + st->db = NULL; + } + break; + default: + break; + } + return (NS_UNAVAIL); +} + + +static int +files_passwd(void *retval, void *mdata, va_list ap) +{ + char keybuf[MAXLOGNAME + 1]; + DBT key, entry; + struct files_state *st; + enum nss_lookup_type how; + const char *name; + struct passwd *pwd; + char *buffer; + size_t bufsize, namesize; + uid_t uid; + uint32_t store; + int rv, stayopen = 0, *errnop; + + name = NULL; + uid = (uid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + keybuf[0] = _PW_KEYBYNAME; + break; + case nss_lt_id: + uid = va_arg(ap, uid_t); + keybuf[0] = _PW_KEYBYUID; + break; + case nss_lt_all: + keybuf[0] = _PW_KEYBYNUM; + break; + default: + rv = NS_NOTFOUND; + goto fin; + } + pwd = va_arg(ap, struct passwd *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = files_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (how == nss_lt_all && st->keynum < 0) { + rv = NS_NOTFOUND; + goto fin; + } + if (st->db == NULL && + (st->db = pwdbopen(&st->version)) == NULL) { + *errnop = errno; + rv = NS_UNAVAIL; + goto fin; + } + if (how == nss_lt_all) + stayopen = 1; + else + stayopen = st->stayopen; + key.data = keybuf; + do { + switch (how) { + case nss_lt_name: + /* MAXLOGNAME includes NUL byte, but we do not + * include the NUL byte in the key. + */ + namesize = strlcpy(&keybuf[1], name, sizeof(keybuf)-1); + if (namesize >= sizeof(keybuf)-1) { + *errnop = EINVAL; + rv = NS_NOTFOUND; + goto fin; + } + key.size = namesize + 1; + break; + case nss_lt_id: + if (st->version < _PWD_CURRENT_VERSION) { + memcpy(&keybuf[1], &uid, sizeof(uid)); + key.size = sizeof(uid) + 1; + } else { + store = htonl(uid); + memcpy(&keybuf[1], &store, sizeof(store)); + key.size = sizeof(store) + 1; + } + break; + case nss_lt_all: + st->keynum++; + if (st->version < _PWD_CURRENT_VERSION) { + memcpy(&keybuf[1], &st->keynum, + sizeof(st->keynum)); + key.size = sizeof(st->keynum) + 1; + } else { + store = htonl(st->keynum); + memcpy(&keybuf[1], &store, sizeof(store)); + key.size = sizeof(store) + 1; + } + break; + } + keybuf[0] = _PW_VERSIONED(keybuf[0], st->version); + rv = st->db->get(st->db, &key, &entry, 0); + if (rv < 0 || rv > 1) { /* should never return > 1 */ + *errnop = errno; + rv = NS_UNAVAIL; + goto fin; + } else if (rv == 1) { + if (how == nss_lt_all) + st->keynum = -1; + rv = NS_NOTFOUND; + goto fin; + } + rv = pwdb_versions[st->version].match(entry.data, entry.size, + how, name, uid); + if (rv != NS_SUCCESS) + continue; + if (entry.size > bufsize) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + memcpy(buffer, entry.data, entry.size); + rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd, + errnop); + } while (how == nss_lt_all && !(rv & NS_TERMINATE)); +fin: + if (st->db != NULL && !stayopen) { + (void)st->db->close(st->db); + st->db = NULL; + } + if (rv == NS_SUCCESS) { + pwd->pw_fields &= ~_PWF_SOURCE; + pwd->pw_fields |= _PWF_FILES; + if (retval != NULL) + *(struct passwd **)retval = pwd; + } + return (rv); +} + + +static int +pwdb_match_entry_v3(char *entry, size_t entrysize, enum nss_lookup_type how, + const char *name, uid_t uid) +{ + const char *p, *eom; + uid_t uid2; + + eom = &entry[entrysize]; + for (p = entry; p < eom; p++) + if (*p == '\0') + break; + if (*p != '\0') + return (NS_NOTFOUND); + if (how == nss_lt_all) + return (NS_SUCCESS); + if (how == nss_lt_name) + return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND); + for (p++; p < eom; p++) + if (*p == '\0') + break; + if (*p != '\0' || (++p) + sizeof(uid) >= eom) + return (NS_NOTFOUND); + memcpy(&uid2, p, sizeof(uid2)); + return (uid == uid2 ? NS_SUCCESS : NS_NOTFOUND); +} + + +static int +pwdb_parse_entry_v3(char *buffer, size_t bufsize, struct passwd *pwd, + int *errnop) +{ + char *p, *eom; + int32_t pw_change, pw_expire; + + /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ + p = buffer; + eom = &buffer[bufsize]; +#define STRING(field) do { \ + (field) = p; \ + while (p < eom && *p != '\0') \ + p++; \ + if (p >= eom) \ + return (NS_NOTFOUND); \ + p++; \ + } while (0) +#define SCALAR(field) do { \ + if (p + sizeof(field) > eom) \ + return (NS_NOTFOUND); \ + memcpy(&(field), p, sizeof(field)); \ + p += sizeof(field); \ + } while (0) + STRING(pwd->pw_name); + STRING(pwd->pw_passwd); + SCALAR(pwd->pw_uid); + SCALAR(pwd->pw_gid); + SCALAR(pw_change); + STRING(pwd->pw_class); + STRING(pwd->pw_gecos); + STRING(pwd->pw_dir); + STRING(pwd->pw_shell); + SCALAR(pw_expire); + SCALAR(pwd->pw_fields); +#undef STRING +#undef SCALAR + pwd->pw_change = pw_change; + pwd->pw_expire = pw_expire; + return (NS_SUCCESS); +} + + +static int +pwdb_match_entry_v4(char *entry, size_t entrysize, enum nss_lookup_type how, + const char *name, uid_t uid) +{ + const char *p, *eom; + uint32_t uid2; + + eom = &entry[entrysize]; + for (p = entry; p < eom; p++) + if (*p == '\0') + break; + if (*p != '\0') + return (NS_NOTFOUND); + if (how == nss_lt_all) + return (NS_SUCCESS); + if (how == nss_lt_name) + return (strcmp(name, entry) == 0 ? NS_SUCCESS : NS_NOTFOUND); + for (p++; p < eom; p++) + if (*p == '\0') + break; + if (*p != '\0' || (++p) + sizeof(uid) >= eom) + return (NS_NOTFOUND); + memcpy(&uid2, p, sizeof(uid2)); + uid2 = ntohl(uid2); + return (uid == (uid_t)uid2 ? NS_SUCCESS : NS_NOTFOUND); +} + + +static int +pwdb_parse_entry_v4(char *buffer, size_t bufsize, struct passwd *pwd, + int *errnop) +{ + char *p, *eom; + uint32_t n; + + /* THIS CODE MUST MATCH THAT IN pwd_mkdb. */ + p = buffer; + eom = &buffer[bufsize]; +#define STRING(field) do { \ + (field) = p; \ + while (p < eom && *p != '\0') \ + p++; \ + if (p >= eom) \ + return (NS_NOTFOUND); \ + p++; \ + } while (0) +#define SCALAR(field) do { \ + if (p + sizeof(n) > eom) \ + return (NS_NOTFOUND); \ + memcpy(&n, p, sizeof(n)); \ + (field) = ntohl(n); \ + p += sizeof(n); \ + } while (0) + STRING(pwd->pw_name); + STRING(pwd->pw_passwd); + SCALAR(pwd->pw_uid); + SCALAR(pwd->pw_gid); + SCALAR(pwd->pw_change); + STRING(pwd->pw_class); + STRING(pwd->pw_gecos); + STRING(pwd->pw_dir); + STRING(pwd->pw_shell); + SCALAR(pwd->pw_expire); + SCALAR(pwd->pw_fields); +#undef STRING +#undef SCALAR + return (NS_SUCCESS); +} + + +#ifdef HESIOD +/* + * dns backend + */ +static void +dns_endstate(void *p) +{ + free(p); +} + + +static int +dns_setpwent(void *retval, void *mdata, va_list ap) +{ + struct dns_state *st; + int rv; + + rv = dns_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + st->counter = 0; + return (NS_UNAVAIL); +} + + +static int +dns_passwd(void *retval, void *mdata, va_list ap) +{ + char buf[HESIOD_NAME_MAX]; + struct dns_state *st; + struct passwd *pwd; + const char *name, *label; + void *ctx; + char *buffer, **hes; + size_t bufsize, linesize; + uid_t uid; + enum nss_lookup_type how; + int rv, *errnop; + + ctx = NULL; + hes = NULL; + name = NULL; + uid = (uid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + break; + case nss_lt_id: + uid = va_arg(ap, uid_t); + break; + case nss_lt_all: + break; + } + pwd = va_arg(ap, struct passwd *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = dns_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (hesiod_init(&ctx) != 0) { + *errnop = errno; + rv = NS_UNAVAIL; + goto fin; + } + do { + rv = NS_NOTFOUND; + switch (how) { + case nss_lt_name: + label = name; + break; + case nss_lt_id: + if (snprintf(buf, sizeof(buf), "%lu", + (unsigned long)uid) >= sizeof(buf)) + goto fin; + label = buf; + break; + case nss_lt_all: + if (st->counter < 0) + goto fin; + if (snprintf(buf, sizeof(buf), "passwd-%ld", + st->counter++) >= sizeof(buf)) + goto fin; + label = buf; + break; + } + hes = hesiod_resolve(ctx, label, + how == nss_lt_id ? "uid" : "passwd"); + if (hes == NULL) { + if (how == nss_lt_all) + st->counter = -1; + if (errno != ENOENT) + *errnop = errno; + goto fin; + } + rv = __pw_match_entry(hes[0], strlen(hes[0]), how, name, uid); + if (rv != NS_SUCCESS) { + hesiod_free_list(ctx, hes); + hes = NULL; + continue; + } + linesize = strlcpy(buffer, hes[0], bufsize); + if (linesize >= bufsize) { + *errnop = ERANGE; + rv = NS_RETURN; + continue; + } + hesiod_free_list(ctx, hes); + hes = NULL; + rv = __pw_parse_entry(buffer, bufsize, pwd, 0, errnop); + } while (how == nss_lt_all && !(rv & NS_TERMINATE)); +fin: + if (hes != NULL) + hesiod_free_list(ctx, hes); + if (ctx != NULL) + hesiod_end(ctx); + if (rv == NS_SUCCESS) { + pwd->pw_fields &= ~_PWF_SOURCE; + pwd->pw_fields |= _PWF_HESIOD; + if (retval != NULL) + *(struct passwd **)retval = pwd; + } + return (rv); +} +#endif /* HESIOD */ + + +#ifdef YP +/* + * nis backend + */ +static void +nis_endstate(void *p) +{ + free(((struct nis_state *)p)->key); + free(p); +} + +/* + * Test for the presence of special FreeBSD-specific master.passwd.by* + * maps. We do this using yp_order(). If it fails, then either the server + * doesn't have the map, or the YPPROC_ORDER procedure isn't supported by + * the server (Sun NIS+ servers in YP compat mode behave this way). If + * the master.passwd.by* maps don't exist, then let the lookup routine try + * the regular passwd.by* maps instead. If the lookup routine fails, it + * can return an error as needed. + */ +static int +nis_map(char *domain, enum nss_lookup_type how, char *buffer, size_t bufsize, + int *master) +{ + int rv, order; + + *master = 0; + if (geteuid() == 0) { + if (snprintf(buffer, bufsize, "master.passwd.by%s", + (how == nss_lt_id) ? "uid" : "name") >= bufsize) + return (NS_UNAVAIL); + rv = yp_order(domain, buffer, &order); + if (rv == 0) { + *master = 1; + return (NS_SUCCESS); + } + } + + if (snprintf(buffer, bufsize, "passwd.by%s", + (how == nss_lt_id) ? "uid" : "name") >= bufsize) + return (NS_UNAVAIL); + + return (NS_SUCCESS); +} + + +static int +nis_adjunct(char *domain, const char *name, char *buffer, size_t bufsize) +{ + int rv; + char *result, *p, *q, *eor; + int resultlen; + + result = NULL; + rv = yp_match(domain, "passwd.adjunct.byname", name, strlen(name), + &result, &resultlen); + if (rv != 0) + rv = 1; + else { + eor = &result[resultlen]; + p = memchr(result, ':', eor - result); + if (p != NULL && ++p < eor && + (q = memchr(p, ':', eor - p)) != NULL) { + if (q - p >= bufsize) + rv = -1; + else { + memcpy(buffer, p, q - p); + buffer[q - p] ='\0'; + } + } else + rv = 1; + } + free(result); + return (rv); +} + + +static int +nis_setpwent(void *retval, void *mdata, va_list ap) +{ + struct nis_state *st; + int rv; + + rv = nis_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + st->done = 0; + free(st->key); + st->key = NULL; + return (NS_UNAVAIL); +} + + +static int +nis_passwd(void *retval, void *mdata, va_list ap) +{ + char map[YPMAXMAP]; + struct nis_state *st; + struct passwd *pwd; + const char *name; + char *buffer, *key, *result; + size_t bufsize; + uid_t uid; + enum nss_lookup_type how; + int *errnop, keylen, resultlen, rv, master; + + name = NULL; + uid = (uid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + break; + case nss_lt_id: + uid = va_arg(ap, uid_t); + break; + case nss_lt_all: + break; + } + pwd = va_arg(ap, struct passwd *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = nis_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (st->domain[0] == '\0') { + if (getdomainname(st->domain, sizeof(st->domain)) != 0) { + *errnop = errno; + return (NS_UNAVAIL); + } + } + rv = nis_map(st->domain, how, map, sizeof(map), &master); + if (rv != NS_SUCCESS) + return (rv); + result = NULL; + do { + rv = NS_NOTFOUND; + switch (how) { + case nss_lt_name: + if (strlcpy(buffer, name, bufsize) >= bufsize) + goto erange; + break; + case nss_lt_id: + if (snprintf(buffer, bufsize, "%lu", + (unsigned long)uid) >= bufsize) + goto erange; + break; + case nss_lt_all: + if (st->done) + goto fin; + break; + } + result = NULL; + if (how == nss_lt_all) { + if (st->key == NULL) + rv = yp_first(st->domain, map, &st->key, + &st->keylen, &result, &resultlen); + else { + key = st->key; + keylen = st->keylen; + st->key = NULL; + rv = yp_next(st->domain, map, key, keylen, + &st->key, &st->keylen, &result, + &resultlen); + free(key); + } + if (rv != 0) { + free(result); + free(st->key); + st->key = NULL; + if (rv == YPERR_NOMORE) + st->done = 1; + else + rv = NS_UNAVAIL; + goto fin; + } + } else { + rv = yp_match(st->domain, map, buffer, strlen(buffer), + &result, &resultlen); + if (rv == YPERR_KEY) { + rv = NS_NOTFOUND; + continue; + } else if (rv != 0) { + free(result); + rv = NS_UNAVAIL; + continue; + } + } + if (resultlen >= bufsize) { + free(result); + goto erange; + } + memcpy(buffer, result, resultlen); + buffer[resultlen] = '\0'; + free(result); + rv = __pw_match_entry(buffer, resultlen, how, name, uid); + if (rv == NS_SUCCESS) + rv = __pw_parse_entry(buffer, resultlen, pwd, master, + errnop); + } while (how == nss_lt_all && !(rv & NS_TERMINATE)); +fin: + if (rv == NS_SUCCESS) { + if (strstr(pwd->pw_passwd, "##") != NULL) { + rv = nis_adjunct(st->domain, pwd->pw_name, + &buffer[resultlen+1], bufsize-resultlen-1); + if (rv < 0) + goto erange; + else if (rv == 0) + pwd->pw_passwd = &buffer[resultlen+1]; + } + pwd->pw_fields &= ~_PWF_SOURCE; + pwd->pw_fields |= _PWF_NIS; + if (retval != NULL) + *(struct passwd **)retval = pwd; + rv = NS_SUCCESS; + } + return (rv); +erange: + *errnop = ERANGE; + return (NS_RETURN); +} +#endif /* YP */ + + +/* + * compat backend + */ +static void +compat_clear_template(struct passwd *template) +{ + + free(template->pw_passwd); + free(template->pw_gecos); + free(template->pw_dir); + free(template->pw_shell); + memset(template, 0, sizeof(*template)); +} + + +static int +compat_set_template(struct passwd *src, struct passwd *template) +{ + + compat_clear_template(template); +#ifdef PW_OVERRIDE_PASSWD + if ((src->pw_fields & _PWF_PASSWD) && + (template->pw_passwd = strdup(src->pw_passwd)) == NULL) + goto enomem; +#endif + if (src->pw_fields & _PWF_UID) + template->pw_uid = src->pw_uid; + if (src->pw_fields & _PWF_GID) + template->pw_gid = src->pw_gid; + if ((src->pw_fields & _PWF_GECOS) && + (template->pw_gecos = strdup(src->pw_gecos)) == NULL) + goto enomem; + if ((src->pw_fields & _PWF_DIR) && + (template->pw_dir = strdup(src->pw_dir)) == NULL) + goto enomem; + if ((src->pw_fields & _PWF_SHELL) && + (template->pw_shell = strdup(src->pw_shell)) == NULL) + goto enomem; + template->pw_fields = src->pw_fields; + return (0); +enomem: + syslog(LOG_ERR, "getpwent memory allocation failure"); + return (-1); +} + + +static int +compat_use_template(struct passwd *pwd, struct passwd *template, char *buffer, + size_t bufsize) +{ + struct passwd hold; + char *copy, *p, *q, *eob; + size_t n; + + /* We cannot know the layout of the password fields in `buffer', + * so we have to copy everything. + */ + if (template->pw_fields == 0) /* nothing to fill-in */ + return (0); + n = 0; + n += pwd->pw_name != NULL ? strlen(pwd->pw_name) + 1 : 0; + n += pwd->pw_passwd != NULL ? strlen(pwd->pw_passwd) + 1 : 0; + n += pwd->pw_class != NULL ? strlen(pwd->pw_class) + 1 : 0; + n += pwd->pw_gecos != NULL ? strlen(pwd->pw_gecos) + 1 : 0; + n += pwd->pw_dir != NULL ? strlen(pwd->pw_dir) + 1 : 0; + n += pwd->pw_shell != NULL ? strlen(pwd->pw_shell) + 1 : 0; + copy = malloc(n); + if (copy == NULL) { + syslog(LOG_ERR, "getpwent memory allocation failure"); + return (ENOMEM); + } + p = copy; + eob = ©[n]; +#define COPY(field) do { \ + if (pwd->field == NULL) \ + hold.field = NULL; \ + else { \ + hold.field = p; \ + p += strlcpy(p, pwd->field, eob-p) + 1; \ + } \ +} while (0) + COPY(pw_name); + COPY(pw_passwd); + COPY(pw_class); + COPY(pw_gecos); + COPY(pw_dir); + COPY(pw_shell); +#undef COPY + p = buffer; + eob = &buffer[bufsize]; +#define COPY(field, flag) do { \ + q = (template->pw_fields & flag) ? template->field : hold.field; \ + if (q == NULL) \ + pwd->field = NULL; \ + else { \ + pwd->field = p; \ + if ((n = strlcpy(p, q, eob-p)) >= eob-p) { \ + free(copy); \ + return (ERANGE); \ + } \ + p += n + 1; \ + } \ +} while (0) + COPY(pw_name, 0); +#ifdef PW_OVERRIDE_PASSWD + COPY(pw_passwd, _PWF_PASSWD); +#else + COPY(pw_passwd, 0); +#endif + COPY(pw_class, 0); + COPY(pw_gecos, _PWF_GECOS); + COPY(pw_dir, _PWF_DIR); + COPY(pw_shell, _PWF_SHELL); +#undef COPY +#define COPY(field, flag) do { \ + if (template->pw_fields & flag) \ + pwd->field = template->field; \ +} while (0) + COPY(pw_uid, _PWF_UID); + COPY(pw_gid, _PWF_GID); +#undef COPY + free(copy); + return (0); +} + + +static int +compat_exclude(const char *name, DB **db) +{ + DBT key, data; + + if (*db == NULL && + (*db = dbopen(NULL, O_RDWR, 600, DB_HASH, 0)) == NULL) + return (errno); + key.size = strlen(name); + key.data = (char *)name; + data.size = 0; + data.data = NULL; + + if ((*db)->put(*db, &key, &data, 0) == -1) + return (errno); + return (0); +} + + +static int +compat_is_excluded(const char *name, DB *db) +{ + DBT key, data; + + if (db == NULL) + return (0); + key.size = strlen(name); + key.data = (char *)name; + return (db->get(db, &key, &data, 0) == 0); +} + + +static int +compat_redispatch(struct compat_state *st, enum nss_lookup_type how, + enum nss_lookup_type lookup_how, const char *name, const char *lookup_name, + uid_t uid, struct passwd *pwd, char *buffer, size_t bufsize, int *errnop) +{ + static const ns_src compatsrc[] = { +#ifdef YP + { NSSRC_NIS, NS_SUCCESS }, +#endif + { NULL, 0 } + }; + ns_dtab dtab[] = { +#ifdef YP + { NSSRC_NIS, nis_passwd, NULL }, +#endif +#ifdef HESIOD + { NSSRC_DNS, dns_passwd, NULL }, +#endif + { NULL, NULL, NULL } + }; + void *discard; + int e, i, rv; + + for (i = 0; i < (int)(nitems(dtab) - 1); i++) + dtab[i].mdata = (void *)lookup_how; +more: + __pw_initpwd(pwd); + switch (lookup_how) { + case nss_lt_all: + rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, + "getpwent_r", compatsrc, pwd, buffer, bufsize, + errnop); + break; + case nss_lt_id: + rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, + "getpwuid_r", compatsrc, uid, pwd, buffer, + bufsize, errnop); + break; + case nss_lt_name: + rv = _nsdispatch(&discard, dtab, NSDB_PASSWD_COMPAT, + "getpwnam_r", compatsrc, lookup_name, pwd, buffer, + bufsize, errnop); + break; + default: + return (NS_UNAVAIL); + } + if (rv != NS_SUCCESS) + return (rv); + if (compat_is_excluded(pwd->pw_name, st->exclude)) { + if (how == nss_lt_all) + goto more; + return (NS_NOTFOUND); + } + e = compat_use_template(pwd, &st->template, buffer, bufsize); + if (e != 0) { + *errnop = e; + if (e == ERANGE) + return (NS_RETURN); + else + return (NS_UNAVAIL); + } + switch (how) { + case nss_lt_name: + if (strcmp(name, pwd->pw_name) != 0) + return (NS_NOTFOUND); + break; + case nss_lt_id: + if (uid != pwd->pw_uid) + return (NS_NOTFOUND); + break; + default: + break; + } + return (NS_SUCCESS); +} + + +static void +compat_endstate(void *p) +{ + struct compat_state *st; + + if (p == NULL) + return; + st = (struct compat_state *)p; + if (st->db != NULL) + st->db->close(st->db); + if (st->exclude != NULL) + st->exclude->close(st->exclude); + compat_clear_template(&st->template); + free(p); +} + + +static int +compat_setpwent(void *retval, void *mdata, va_list ap) +{ + static const ns_src compatsrc[] = { +#ifdef YP + { NSSRC_NIS, NS_SUCCESS }, +#endif + { NULL, 0 } + }; + ns_dtab dtab[] = { +#ifdef YP + { NSSRC_NIS, nis_setpwent, NULL }, +#endif +#ifdef HESIOD + { NSSRC_DNS, dns_setpwent, NULL }, +#endif + { NULL, NULL, NULL } + }; + struct compat_state *st; + int rv, stayopen; + +#define set_setent(x, y) do { \ + int i; \ + for (i = 0; i < (int)(nitems(x) - 1); i++) \ + x[i].mdata = (void *)y; \ +} while (0) + + rv = compat_getstate(&st); + if (rv != 0) + return (NS_UNAVAIL); + switch ((enum constants)(uintptr_t)mdata) { + case SETPWENT: + stayopen = va_arg(ap, int); + st->keynum = 0; + if (stayopen) + st->db = pwdbopen(&st->version); + st->stayopen = stayopen; + set_setent(dtab, mdata); + (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "setpwent", + compatsrc, 0); + break; + case ENDPWENT: + if (st->db != NULL) { + (void)st->db->close(st->db); + st->db = NULL; + } + set_setent(dtab, mdata); + (void)_nsdispatch(NULL, dtab, NSDB_PASSWD_COMPAT, "endpwent", + compatsrc, 0); + break; + default: + break; + } + return (NS_UNAVAIL); +#undef set_setent +} + + +static int +compat_passwd(void *retval, void *mdata, va_list ap) +{ + char keybuf[MAXLOGNAME + 1]; + DBT key, entry; + pwkeynum keynum; + struct compat_state *st; + enum nss_lookup_type how; + const char *name; + struct passwd *pwd; + char *buffer, *pw_name; + char *host, *user, *domain; + size_t bufsize; + uid_t uid; + uint32_t store; + int rv, from_compat, stayopen, *errnop; + + from_compat = 0; + name = NULL; + uid = (uid_t)-1; + how = (enum nss_lookup_type)(uintptr_t)mdata; + switch (how) { + case nss_lt_name: + name = va_arg(ap, const char *); + break; + case nss_lt_id: + uid = va_arg(ap, uid_t); + break; + case nss_lt_all: + break; + default: + rv = NS_NOTFOUND; + goto fin; + } + pwd = va_arg(ap, struct passwd *); + buffer = va_arg(ap, char *); + bufsize = va_arg(ap, size_t); + errnop = va_arg(ap, int *); + *errnop = compat_getstate(&st); + if (*errnop != 0) + return (NS_UNAVAIL); + if (how == nss_lt_all && st->keynum < 0) { + rv = NS_NOTFOUND; + goto fin; + } + if (st->db == NULL && + (st->db = pwdbopen(&st->version)) == NULL) { + *errnop = errno; + rv = NS_UNAVAIL; + goto fin; + } + if (how == nss_lt_all) { + if (st->keynum < 0) { + rv = NS_NOTFOUND; + goto fin; + } + keynum = st->keynum; + stayopen = 1; + } else { + keynum = 0; + stayopen = st->stayopen; + } +docompat: + rv = NS_NOTFOUND; + switch (st->compat) { + case COMPAT_MODE_ALL: + rv = compat_redispatch(st, how, how, name, name, uid, pwd, + buffer, bufsize, errnop); + if (rv != NS_SUCCESS) + st->compat = COMPAT_MODE_OFF; + break; + case COMPAT_MODE_NETGROUP: + /* XXX getnetgrent is not thread-safe. */ + do { + rv = getnetgrent(&host, &user, &domain); + if (rv == 0) { + endnetgrent(); + st->compat = COMPAT_MODE_OFF; + rv = NS_NOTFOUND; + continue; + } else if (user == NULL || user[0] == '\0') + continue; + rv = compat_redispatch(st, how, nss_lt_name, name, + user, uid, pwd, buffer, bufsize, errnop); + } while (st->compat == COMPAT_MODE_NETGROUP && + !(rv & NS_TERMINATE)); + break; + case COMPAT_MODE_NAME: + rv = compat_redispatch(st, how, nss_lt_name, name, st->name, + uid, pwd, buffer, bufsize, errnop); + free(st->name); + st->name = NULL; + st->compat = COMPAT_MODE_OFF; + break; + default: + break; + } + if (rv & NS_TERMINATE) { + from_compat = 1; + goto fin; + } + key.data = keybuf; + rv = NS_NOTFOUND; + while (keynum >= 0) { + keynum++; + if (st->version < _PWD_CURRENT_VERSION) { + memcpy(&keybuf[1], &keynum, sizeof(keynum)); + key.size = sizeof(keynum) + 1; + } else { + store = htonl(keynum); + memcpy(&keybuf[1], &store, sizeof(store)); + key.size = sizeof(store) + 1; + } + keybuf[0] = _PW_VERSIONED(_PW_KEYBYNUM, st->version); + rv = st->db->get(st->db, &key, &entry, 0); + if (rv < 0 || rv > 1) { /* should never return > 1 */ + *errnop = errno; + rv = NS_UNAVAIL; + goto fin; + } else if (rv == 1) { + keynum = -1; + rv = NS_NOTFOUND; + goto fin; + } + pw_name = (char *)entry.data; + switch (pw_name[0]) { + case '+': + switch (pw_name[1]) { + case '\0': + st->compat = COMPAT_MODE_ALL; + break; + case '@': + setnetgrent(&pw_name[2]); + st->compat = COMPAT_MODE_NETGROUP; + break; + default: + st->name = strdup(&pw_name[1]); + if (st->name == NULL) { + syslog(LOG_ERR, + "getpwent memory allocation failure"); + *errnop = ENOMEM; + rv = NS_UNAVAIL; + break; + } + st->compat = COMPAT_MODE_NAME; + } + if (entry.size > bufsize) { + *errnop = ERANGE; + rv = NS_RETURN; + goto fin; + } + memcpy(buffer, entry.data, entry.size); + rv = pwdb_versions[st->version].parse(buffer, + entry.size, pwd, errnop); + if (rv != NS_SUCCESS) + ; + else if (compat_set_template(pwd, &st->template) < 0) { + *errnop = ENOMEM; + rv = NS_UNAVAIL; + goto fin; + } + goto docompat; + case '-': + switch (pw_name[1]) { + case '\0': + /* XXX Maybe syslog warning */ + continue; + case '@': + setnetgrent(&pw_name[2]); + while (getnetgrent(&host, &user, &domain) != + 0) { + if (user != NULL && user[0] != '\0') + compat_exclude(user, + &st->exclude); + } + endnetgrent(); + continue; + default: + compat_exclude(&pw_name[1], &st->exclude); + continue; + } + break; + default: + break; + } + if (compat_is_excluded((char *)entry.data, st->exclude)) + continue; + rv = pwdb_versions[st->version].match(entry.data, entry.size, + how, name, uid); + if (rv == NS_RETURN) + break; + else if (rv != NS_SUCCESS) + continue; + if (entry.size > bufsize) { + *errnop = ERANGE; + rv = NS_RETURN; + break; + } + memcpy(buffer, entry.data, entry.size); + rv = pwdb_versions[st->version].parse(buffer, entry.size, pwd, + errnop); + if (rv & NS_TERMINATE) + break; + } +fin: + if (how == nss_lt_all) + st->keynum = keynum; + if (st->db != NULL && !stayopen) { + (void)st->db->close(st->db); + st->db = NULL; + } + if (rv == NS_SUCCESS) { + if (!from_compat) { + pwd->pw_fields &= ~_PWF_SOURCE; + pwd->pw_fields |= _PWF_FILES; + } + if (retval != NULL) + *(struct passwd **)retval = pwd; + } + return (rv); +} + + +/* + * common passwd line matching and parsing + */ +int +__pw_match_entry(const char *entry, size_t entrysize, enum nss_lookup_type how, + const char *name, uid_t uid) +{ + const char *p, *eom; + char *q; + size_t len; + unsigned long m; + + eom = entry + entrysize; + for (p = entry; p < eom; p++) + if (*p == ':') + break; + if (*p != ':') + return (NS_NOTFOUND); + if (how == nss_lt_all) + return (NS_SUCCESS); + if (how == nss_lt_name) { + len = strlen(name); + if (len == (p - entry) && memcmp(name, entry, len) == 0) + return (NS_SUCCESS); + else + return (NS_NOTFOUND); + } + for (p++; p < eom; p++) + if (*p == ':') + break; + if (*p != ':') + return (NS_NOTFOUND); + m = strtoul(++p, &q, 10); + if (q[0] != ':' || (uid_t)m != uid) + return (NS_NOTFOUND); + else + return (NS_SUCCESS); +} + + +/* XXX buffer must be NUL-terminated. errnop is not set correctly. */ +int +__pw_parse_entry(char *buffer, size_t bufsize __unused, struct passwd *pwd, + int master, int *errnop __unused) +{ + + if (__pw_scan(buffer, pwd, master ? _PWSCAN_MASTER : 0) == 0) + return (NS_NOTFOUND); + else + return (NS_SUCCESS); +} diff --git a/lib/libc/gen/getttyent.3 b/lib/libc/gen/getttyent.3 new file mode 100644 index 000000000000..bf38f417ac58 --- /dev/null +++ b/lib/libc/gen/getttyent.3 @@ -0,0 +1,211 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 17, 1996 +.Dt GETTTYENT 3 +.Os +.Sh NAME +.Nm getttyent , +.Nm getttynam , +.Nm setttyent , +.Nm endttyent , +.Nm isdialuptty , +.Nm isnettty +.Nd +.Xr ttys 5 +file routines +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In ttyent.h +.Ft struct ttyent * +.Fn getttyent void +.Ft struct ttyent * +.Fn getttynam "const char *name" +.Ft int +.Fn setttyent void +.Ft int +.Fn endttyent void +.Ft int +.Fn isdialuptty "const char *name" +.Ft int +.Fn isnettty "const char *name" +.Sh DESCRIPTION +The +.Fn getttyent , +and +.Fn getttynam +functions +each return a pointer to an object, with the following structure, +containing the broken-out fields of a line from the tty description +file. +.Bd -literal +struct ttyent { + char *ty_name; /* terminal device name */ + char *ty_getty; /* command to execute, usually getty */ + char *ty_type; /* terminal type for termcap */ +#define TTY_ON 0x01 /* enable logins (start ty_getty program) */ +#define TTY_SECURE 0x02 /* allow uid of 0 to login */ +#define TTY_DIALUP 0x04 /* is a dialup tty */ +#define TTY_NETWORK 0x08 /* is a network tty */ +#define TTY_IFEXISTS 0x10 /* configured as "onifexists" */ +#define TTY_IFCONSOLE 0x20 /* configured as "onifconsole" */ + int ty_status; /* status flags */ + char *ty_window; /* command to start up window manager */ + char *ty_comment; /* comment field */ + char *ty_group; /* tty group name */ +}; +.Ed +.Pp +The fields are as follows: +.Bl -tag -width ty_comment +.It Fa ty_name +The name of the character-special file. +.It Fa ty_getty +The name of the command invoked by +.Xr init 8 +to initialize tty line characteristics. +.It Fa ty_type +The name of the default terminal type connected to this tty line. +.It Fa ty_status +A mask of bit fields which indicate various actions allowed on this +tty line. +The possible flags are as follows: +.Bl -tag -width TTY_NETWORK +.It Dv TTY_ON +Enables logins (i.e., +.Xr init 8 +will start the command referenced by +.Fa ty_getty +on this entry). +.It Dv TTY_SECURE +Allow users with a uid of 0 to login on this terminal. +.It Dv TTY_DIALUP +Identifies a tty as a dialin line. +If this flag is set, then +.Fn isdialuptty +will return a non-zero value. +.It Dv TTY_NETWORK +Identifies a tty used for network connections. +If this flag is set, then +.Fn isnettty +will return a non-zero value. +.It Dv TTY_IFEXISTS +Identifies a tty that does not necessarily exist. +.It Dv TTY_IFCONSOLE +Identifies a tty that might be a system console. +.El +.It Fa ty_window +The command to execute for a window system associated with the line. +.It Fa ty_group +A group name to which the tty belongs. +If no group is specified in the ttys description file, +then the tty is placed in an anonymous group called "none". +.It Fa ty_comment +Any trailing comment field, with any leading hash marks (``#'') or +whitespace removed. +.El +.Pp +If any of the fields pointing to character strings are unspecified, +they are returned as null pointers. +The field +.Fa ty_status +will be zero if no flag values are specified. +.Pp +See +.Xr ttys 5 +for a more complete discussion of the meaning and usage of the +fields. +.Pp +The +.Fn getttyent +function +reads the next line from the ttys file, opening the file if necessary. +The +.Fn setttyent +function +rewinds the file if open, or opens the file if it is unopened. +The +.Fn endttyent +function +closes any open files. +.Pp +The +.Fn getttynam +function +searches from the beginning of the file until a matching +.Fa name +is found +(or until +.Dv EOF +is encountered). +.Sh RETURN VALUES +The routines +.Fn getttyent +and +.Fn getttynam +return a null pointer on +.Dv EOF +or error. +The +.Fn setttyent +function +and +.Fn endttyent +return 0 on failure and 1 on success. +.Pp +The routines +.Fn isdialuptty +and +.Fn isnettty +return non-zero if the dialup or network flag is set for the +tty entry relating to the tty named by the argument, and +zero otherwise. +.Sh FILES +.Bl -tag -width /etc/ttys -compact +.It Pa /etc/ttys +.El +.Sh SEE ALSO +.Xr login 1 , +.Xr gettytab 5 , +.Xr termcap 5 , +.Xr ttys 5 , +.Xr getty 8 , +.Xr init 8 +.Sh HISTORY +The +.Fn getttyent , +.Fn getttynam , +.Fn setttyent , +and +.Fn endttyent +functions appeared in +.Bx 4.3 . +.Sh BUGS +These functions use static data storage; +if the data is needed for future use, it should be +copied before any subsequent calls overwrite it. diff --git a/lib/libc/gen/getttyent.c b/lib/libc/gen/getttyent.c new file mode 100644 index 000000000000..3c92f603ff06 --- /dev/null +++ b/lib/libc/gen/getttyent.c @@ -0,0 +1,312 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sysctl.h> + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ttyent.h> + +static char zapchar; +static FILE *tf; +static size_t lbsize; +static char *line; + +#define MALLOCCHUNK 100 + +static char *skip(char *); +static char *value(char *); + +struct ttyent * +getttynam(const char *tty) +{ + struct ttyent *t; + + if (strncmp(tty, "/dev/", 5) == 0) + tty += 5; + setttyent(); + while ( (t = getttyent()) ) + if (!strcmp(tty, t->ty_name)) + break; + endttyent(); + return (t); +} + +static int +auto_tty_status(const char *ty_name) +{ + size_t len; + char *buf, *cons, *nextcons; + int rv; + + rv = TTY_IFCONSOLE; + + /* Check if this is an enabled kernel console line */ + buf = NULL; + if (sysctlbyname("kern.console", NULL, &len, NULL, 0) == -1) + return (rv); /* Errors mean don't enable */ + buf = malloc(len); + if (sysctlbyname("kern.console", buf, &len, NULL, 0) == -1) + goto done; + + if ((cons = strchr(buf, '/')) == NULL) + goto done; + *cons = '\0'; + nextcons = buf; + while ((cons = strsep(&nextcons, ",")) != NULL && strlen(cons) != 0) { + if (strcmp(cons, ty_name) == 0) { + rv |= TTY_ON; + break; + } + } + +done: + free(buf); + return (rv); +} + +static int +auto_exists_status(const char *ty_name) +{ + struct stat sb; + char *dev; + int rv; + + rv = TTY_IFEXISTS; + if (*ty_name == '/') + asprintf(&dev, "%s", ty_name); + else + asprintf(&dev, "/dev/%s", ty_name); + if (dev != NULL && stat(dev, &sb) == 0) + rv |= TTY_ON; + free(dev); + return (rv); +} + +struct ttyent * +getttyent(void) +{ + static struct ttyent tty; + char *p; + int c; + size_t i; + + if (!tf && !setttyent()) + return (NULL); + for (;;) { + if (!fgets(p = line, lbsize, tf)) + return (NULL); + /* extend buffer if line was too big, and retry */ + while (!strchr(p, '\n') && !feof(tf)) { + i = strlen(p); + lbsize += MALLOCCHUNK; + if ((p = realloc(line, lbsize)) == NULL) { + (void)endttyent(); + return (NULL); + } + line = p; + if (!fgets(&line[i], lbsize - i, tf)) + return (NULL); + } + while (isspace((unsigned char)*p)) + ++p; + if (*p && *p != '#') + break; + } + +#define scmp(e) !strncmp(p, e, sizeof(e) - 1) && isspace((unsigned char)p[sizeof(e) - 1]) +#define vcmp(e) !strncmp(p, e, sizeof(e) - 1) && p[sizeof(e) - 1] == '=' + + zapchar = 0; + tty.ty_name = p; + tty.ty_status = 0; + tty.ty_window = NULL; + tty.ty_group = _TTYS_NOGROUP; + + p = skip(p); + if (!*(tty.ty_getty = p)) + tty.ty_getty = tty.ty_type = NULL; + else { + p = skip(p); + if (!*(tty.ty_type = p)) + tty.ty_type = NULL; + else { + /* compatibility kludge: handle network/dialup specially */ + if (scmp(_TTYS_DIALUP)) + tty.ty_status |= TTY_DIALUP; + else if (scmp(_TTYS_NETWORK)) + tty.ty_status |= TTY_NETWORK; + p = skip(p); + } + } + + for (; *p; p = skip(p)) { + if (scmp(_TTYS_OFF)) + tty.ty_status &= ~TTY_ON; + else if (scmp(_TTYS_ON)) + tty.ty_status |= TTY_ON; + else if (scmp(_TTYS_ONIFCONSOLE)) + tty.ty_status |= auto_tty_status(tty.ty_name); + else if (scmp(_TTYS_ONIFEXISTS)) + tty.ty_status |= auto_exists_status(tty.ty_name); + else if (scmp(_TTYS_SECURE)) + tty.ty_status |= TTY_SECURE; + else if (scmp(_TTYS_INSECURE)) + tty.ty_status &= ~TTY_SECURE; + else if (scmp(_TTYS_DIALUP)) + tty.ty_status |= TTY_DIALUP; + else if (scmp(_TTYS_NETWORK)) + tty.ty_status |= TTY_NETWORK; + else if (vcmp(_TTYS_WINDOW)) + tty.ty_window = value(p); + else if (vcmp(_TTYS_GROUP)) + tty.ty_group = value(p); + else + break; + } + + if (zapchar == '#' || *p == '#') + while ((c = *++p) == ' ' || c == '\t') + ; + tty.ty_comment = p; + if (*p == 0) + tty.ty_comment = 0; + if ((p = strchr(p, '\n'))) + *p = '\0'; + return (&tty); +} + +#define QUOTED 1 + +/* + * Skip over the current field, removing quotes, and return a pointer to + * the next field. + */ +static char * +skip(char *p) +{ + char *t; + int c, q; + + for (q = 0, t = p; (c = *p) != '\0'; p++) { + if (c == '"') { + q ^= QUOTED; /* obscure, but nice */ + continue; + } + if (q == QUOTED && *p == '\\' && *(p+1) == '"') + p++; + *t++ = *p; + if (q == QUOTED) + continue; + if (c == '#') { + zapchar = c; + *p = 0; + break; + } + if (c == '\t' || c == ' ' || c == '\n') { + zapchar = c; + *p++ = 0; + while ((c = *p) == '\t' || c == ' ' || c == '\n') + p++; + break; + } + } + *--t = '\0'; + return (p); +} + +static char * +value(char *p) +{ + + return ((p = strchr(p, '=')) ? ++p : NULL); +} + +int +setttyent(void) +{ + + if (line == NULL) { + if ((line = malloc(MALLOCCHUNK)) == NULL) + return (0); + lbsize = MALLOCCHUNK; + } + if (tf) { + rewind(tf); + return (1); + } else if ( (tf = fopen(_PATH_TTYS, "re")) ) + return (1); + return (0); +} + +int +endttyent(void) +{ + int rval; + + /* + * NB: Don't free `line' because getttynam() + * may still be referencing it + */ + if (tf) { + rval = (fclose(tf) != EOF); + tf = NULL; + return (rval); + } + return (1); +} + +static int +isttystat(const char *tty, int flag) +{ + struct ttyent *t; + + return ((t = getttynam(tty)) == NULL) ? 0 : !!(t->ty_status & flag); +} + + +int +isdialuptty(const char *tty) +{ + + return isttystat(tty, TTY_DIALUP); +} + +int +isnettty(const char *tty) +{ + + return isttystat(tty, TTY_NETWORK); +} diff --git a/lib/libc/gen/getusershell.3 b/lib/libc/gen/getusershell.3 new file mode 100644 index 000000000000..728e87c9d56a --- /dev/null +++ b/lib/libc/gen/getusershell.3 @@ -0,0 +1,96 @@ +.\" $NetBSD: getusershell.3,v 1.6 1999/03/22 19:44:42 garbled Exp $ +.\" +.\" Copyright (c) 1985, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 16, 1999 +.Dt GETUSERSHELL 3 +.Os +.Sh NAME +.Nm getusershell , +.Nm setusershell , +.Nm endusershell +.Nd get valid user shells +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft char * +.Fn getusershell void +.Ft void +.Fn setusershell void +.Ft void +.Fn endusershell void +.Sh DESCRIPTION +The +.Fn getusershell +function +returns a pointer to a valid user shell as defined by the +system manager in the shells database as described in +.Xr shells 5 . +If the shells database is not available, +.Fn getusershell +behaves as if +.Pa /bin/sh +and +.Pa /bin/csh +were listed. +.Pp +The +.Fn getusershell +function +reads the next +line (opening the file if necessary); +.Fn setusershell +rewinds the file; +.Fn endusershell +closes it. +.Sh FILES +.Bl -tag -width /etc/shells -compact +.It Pa /etc/shells +.El +.Sh DIAGNOSTICS +The routine +.Fn getusershell +returns a null pointer (0) on +.Dv EOF . +.Sh SEE ALSO +.Xr nsswitch.conf 5 , +.Xr shells 5 +.Sh HISTORY +The +.Fn getusershell +function appeared in +.Bx 4.3 . +.Sh BUGS +The +.Fn getusershell +function leaves its result in an internal static object and returns +a pointer to that object. +Subsequent calls to +.Fn getusershell +will modify the same object. diff --git a/lib/libc/gen/getusershell.c b/lib/libc/gen/getusershell.c new file mode 100644 index 000000000000..26c6e326e94d --- /dev/null +++ b/lib/libc/gen/getusershell.c @@ -0,0 +1,258 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: getusershell.c,v 1.17 1999/01/25 01:09:34 lukem Exp $"); + +#include "namespace.h" +#include <sys/param.h> +#include <sys/file.h> + +#include <ctype.h> +#include <errno.h> +#include <nsswitch.h> +#include <paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stringlist.h> +#include <unistd.h> + +#ifdef HESIOD +#include <hesiod.h> +#endif +#ifdef YP +#include <rpc/rpc.h> +#include <rpcsvc/ypclnt.h> +#include <rpcsvc/yp_prot.h> +#endif +#include "un-namespace.h" + +static const char *const *curshell; +static StringList *sl; + +static const char *const *initshells(void); + +/* + * Get a list of shells from "shells" nsswitch database + */ +char * +getusershell(void) +{ + char *ret; + + if (curshell == NULL) + curshell = initshells(); + /*LINTED*/ + ret = (char *)*curshell; + if (ret != NULL) + curshell++; + return (ret); +} + +void +endusershell(void) +{ + if (sl) { + sl_free(sl, 1); + sl = NULL; + } + curshell = NULL; +} + +void +setusershell(void) +{ + + curshell = initshells(); +} + + +static int _local_initshells(void *, void *, va_list); + +/*ARGSUSED*/ +static int +_local_initshells(void *rv, void *cb_data, va_list ap) +{ + char *sp, *cp; + FILE *fp; + char line[MAXPATHLEN + 2]; + + if (sl) + sl_free(sl, 1); + sl = sl_init(); + + if ((fp = fopen(_PATH_SHELLS, "re")) == NULL) + return NS_UNAVAIL; + + while (fgets(line, MAXPATHLEN + 1, fp) != NULL) { + cp = line; + while (*cp != '#' && *cp != '/' && *cp != '\0') + cp++; + if (*cp == '#' || *cp == '\0') + continue; + sp = cp; + while (!isspace(*cp) && *cp != '#' && *cp != '\0') + cp++; + *cp = '\0'; + sl_add(sl, strdup(sp)); + } + (void)fclose(fp); + return NS_SUCCESS; +} + +#ifdef HESIOD +static int _dns_initshells(void *, void *, va_list); + +/*ARGSUSED*/ +static int +_dns_initshells(void *rv, void *cb_data, va_list ap) +{ + char shellname[] = "shells-XXXXX"; + int hsindex, hpi, r; + char **hp; + void *context; + + if (sl) + sl_free(sl, 1); + sl = sl_init(); + r = NS_UNAVAIL; + if (hesiod_init(&context) == -1) + return (r); + + for (hsindex = 0; ; hsindex++) { + snprintf(shellname, sizeof(shellname)-1, "shells-%d", hsindex); + hp = hesiod_resolve(context, shellname, "shells"); + if (hp == NULL) { + if (errno == ENOENT) { + if (hsindex == 0) + r = NS_NOTFOUND; + else + r = NS_SUCCESS; + } + break; + } else { + for (hpi = 0; hp[hpi]; hpi++) + sl_add(sl, hp[hpi]); + free(hp); + } + } + hesiod_end(context); + return (r); +} +#endif /* HESIOD */ + +#ifdef YP +static int _nis_initshells(void *, void *, va_list); + +/*ARGSUSED*/ +static int +_nis_initshells(void *rv, void *cb_data, va_list ap) +{ + static char *ypdomain; + char *key, *data; + char *lastkey; + int keylen, datalen; + int r; + + if (sl) + sl_free(sl, 1); + sl = sl_init(); + + if (ypdomain == NULL) { + switch (yp_get_default_domain(&ypdomain)) { + case 0: + break; + case YPERR_RESRC: + return NS_TRYAGAIN; + default: + return NS_UNAVAIL; + } + } + + /* + * `key' and `data' point to strings dynamically allocated by + * the yp_... functions. + * `data' is directly put into the stringlist of shells. + */ + key = data = NULL; + if (yp_first(ypdomain, "shells", &key, &keylen, &data, &datalen)) + return NS_UNAVAIL; + do { + data[datalen] = '\0'; /* clear trailing \n */ + sl_add(sl, data); + + lastkey = key; + r = yp_next(ypdomain, "shells", lastkey, keylen, + &key, &keylen, &data, &datalen); + free(lastkey); + } while (r == 0); + + if (r == YPERR_NOMORE) { + /* + * `data' and `key' ought to be NULL - do not try to free them. + */ + return NS_SUCCESS; + } + + return NS_UNAVAIL; +} +#endif /* YP */ + +static const char *const * +initshells(void) +{ + static const ns_dtab dtab[] = { + NS_FILES_CB(_local_initshells, NULL) + NS_DNS_CB(_dns_initshells, NULL) + NS_NIS_CB(_nis_initshells, NULL) + { 0 } + }; + if (sl) + sl_free(sl, 1); + sl = sl_init(); + + if (_nsdispatch(NULL, dtab, NSDB_SHELLS, "initshells", __nsdefaultsrc) + != NS_SUCCESS) { + if (sl) + sl_free(sl, 1); + sl = sl_init(); + /* + * Local shells should NOT be added here. They should be + * added in /etc/shells. + */ + sl_add(sl, strdup(_PATH_BSHELL)); + sl_add(sl, strdup(_PATH_CSHELL)); + } + sl_add(sl, NULL); + + return (const char *const *)(sl->sl_str); +} diff --git a/lib/libc/gen/getutxent.3 b/lib/libc/gen/getutxent.3 new file mode 100644 index 000000000000..96d376dc29bc --- /dev/null +++ b/lib/libc/gen/getutxent.3 @@ -0,0 +1,476 @@ +.\" Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 27, 2011 +.Dt GETUTXENT 3 +.Os +.Sh NAME +.Nm endutxent , +.Nm getutxent , +.Nm getutxid , +.Nm getutxline , +.Nm getutxuser , +.Nm pututxline , +.Nm setutxdb , +.Nm setutxent +.Nd user accounting database functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In utmpx.h +.Ft void +.Fn endutxent "void" +.Ft struct utmpx * +.Fn getutxent "void" +.Ft struct utmpx * +.Fn getutxid "const struct utmpx *id" +.Ft struct utmpx * +.Fn getutxline "const struct utmpx *line" +.Ft struct utmpx * +.Fn getutxuser "const char *user" +.Ft struct utmpx * +.Fn pututxline "const struct utmpx *utmpx" +.Ft int +.Fn setutxdb "int type" "const char *file" +.Ft void +.Fn setutxent "void" +.Sh DESCRIPTION +These functions operate on the user accounting database which stores +records of various system activities, such as user login and logouts, +but also system startups and shutdowns and modifications to the system's +clock. +The system stores these records in three databases, each having a +different purpose: +.Bl -tag -width indent +.It Pa /var/run/utx.active +Log of currently active user login sessions. +This file is similar to the traditional +.Pa utmp +file. +This file only contains process related entries, such as user login and +logout records. +.It Pa /var/log/utx.lastlogin +Log of last user login entries per user. +This file is similar to the traditional +.Pa lastlog +file. +This file only contains user login records for users who have at least +logged in once. +.It Pa /var/log/utx.log +Log of all entries, sorted by date of addition. +This file is similar to the traditional +.Pa wtmp +file. +This file may contain any type of record described below. +.El +.Pp +Each entry in these databases is defined by the structure +.Vt utmpx +found in the include file +.In utmpx.h : +.Bd -literal -offset indent +struct utmpx { + short ut_type; /* Type of entry. */ + struct timeval ut_tv; /* Time entry was made. */ + char ut_id[]; /* Record identifier. */ + pid_t ut_pid; /* Process ID. */ + char ut_user[]; /* User login name. */ + char ut_line[]; /* Device name. */ + char ut_host[]; /* Remote hostname. */ +}; +.Ed +.Pp +The +.Fa ut_type +field indicates the type of the log entry, which can have one of the +following values: +.Bl -tag -width LOGIN_PROCESS +.It Dv EMPTY +No valid user accounting information. +.It Dv BOOT_TIME +Identifies time of system boot. +.It Dv SHUTDOWN_TIME +Identifies time of system shutdown. +.It Dv OLD_TIME +Identifies time when system clock changed. +.It Dv NEW_TIME +Identifies time after system clock changed. +.It Dv USER_PROCESS +Identifies a process. +.It Dv INIT_PROCESS +Identifies a process spawned by the init process. +.It Dv LOGIN_PROCESS +Identifies the session leader of a logged-in user. +.It Dv DEAD_PROCESS +Identifies a session leader who has exited. +.El +.Pp +Entries of type +.Dv INIT_PROCESS +and +.Dv LOGIN_PROCESS +are not processed by this implementation. +.Pp +Other fields inside the structure are: +.Bl -tag -width ut_user +.It Fa ut_tv +The time the event occurred. +This field is used for all types of entries, except +.Dv EMPTY . +.It Fa ut_id +An identifier that is used to refer to the entry. +This identifier can be used to remove or replace a login entry by +writing a new entry to the database containing the same value for +.Fa ut_id . +This field is only applicable to entries of type +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +and +.Dv DEAD_PROCESS . +.It Fa ut_pid +The process identifier of the session leader of the login session. +This field is only applicable to entries of type +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +and +.Dv DEAD_PROCESS . +.It Fa ut_user +The user login name corresponding with the login session. +This field is only applicable to entries of type +.Dv USER_PROCESS +and +.Dv INIT_PROCESS . +For +.Dv INIT_PROCESS +entries this entry typically contains the name of the login process. +.It Fa ut_line +The name of the TTY character device, without the leading +.Pa /dev/ +prefix, corresponding with the device used to facilitate the user login +session. +If no TTY character device is used, this field is left blank. +This field is only applicable to entries of type +.Dv USER_PROCESS +and +.Dv LOGIN_PROCESS . +.It Fa ut_host +The network hostname of the remote system, connecting to perform a user +login. +If the user login session is not performed across a network, this field +is left blank. +This field is only applicable to entries of type +.Dv USER_PROCESS . +.El +.Pp +This implementation guarantees all inapplicable fields are discarded. +The +.Fa ut_user , +.Fa ut_line +and +.Fa ut_host +fields of the structure returned by the library functions are also +guaranteed to be null-terminated in this implementation. +.Pp +The +.Fn getutxent +function can be used to read the next entry from the user accounting +database. +.Pp +The +.Fn getutxid +function searches for the next entry in the database of which the +behaviour is based on the +.Fa ut_type +field of +.Fa id . +If +.Fa ut_type +has a value of +.Dv BOOT_TIME , +.Dv SHUTDOWN_TIME , +.Dv OLD_TIME +or +.Dv NEW_TIME , +it will return the next entry whose +.Fa ut_type +has an equal value. +If +.Fa ut_type +has a value of +.Dv USER_PROCESS , +.Dv INIT_PROCESS , +.Dv LOGIN_PROCESS +or +.Dv DEAD_PROCESS , +it will return the next entry whose +.Fa ut_type +has one of the previously mentioned values and whose +.Fa ut_id +is equal. +.Pp +The +.Fn getutxline +function searches for the next entry in the database whose +.Fa ut_type +has a value of +.Dv USER_PROCESS +or +.Dv LOGIN_PROCESS +and whose +.Fa ut_line +is equal to the same field in +.Fa line . +.Pp +The +.Fn getutxuser +function searches for the next entry in the database whose +.Fa ut_type +has a value of +.Dv USER_PROCESS +and whose +.Fa ut_user +is equal to +.Fa user . +.Pp +The previously mentioned functions will automatically try to open the +user accounting database if not already done so. +The +.Fn setutxdb +and +.Fn setutxent +functions allow the database to be opened manually, causing the offset +within the user accounting database to be rewound. +The +.Fn endutxent +function closes the database. +.Pp +The +.Fn setutxent +database always opens the active sessions database. +The +.Fn setutxdb +function opens the database identified by +.Fa type , +whose value is either +.Dv UTXDB_ACTIVE , +.Dv UTXDB_LASTLOGIN +or +.Dv UTXDB_LOG . +It will open a custom file with filename +.Fa file +instead of the system-default if +.Fa file +is not null. +Care must be taken that when using a custom filename, +.Fa type +still has to match with the actual format, since each database may use +its own file format. +.Pp +The +.Fn pututxline +function writes record +.Fa utmpx +to the system-default user accounting databases. +The value of +.Fa ut_type +determines which databases are modified. +.Pp +Entries of type +.Dv SHUTDOWN_TIME , +.Dv OLD_TIME +and +.Dv NEW_TIME +will only be written to +.Pa /var/log/utx.log . +.Pp +Entries of type +.Dv USER_PROCESS +will also be written to +.Pa /var/run/utx.active +and +.Pa /var/log/utx.lastlogin . +.Pp +Entries of type +.Dv DEAD_PROCESS +will only be written to +.Pa /var/log/utx.log +and +.Pa /var/run/utx.active +if a corresponding +.Dv USER_PROCESS , +.Dv INIT_PROCESS +or +.Dv LOGIN_PROCESS +entry whose +.Fa ut_id +is equal has been found in the latter. +.Pp +In addition, entries of type +.Dv BOOT_TIME +and +.Dv SHUTDOWN_TIME +will cause all existing entries in +.Pa /var/run/utx.active +to be discarded. +.Pp +All entries whose type has not been mentioned previously, are discarded +by this implementation of +.Fn pututxline . +This implementation also ignores the value of +.Fa ut_tv . +.Sh RETURN VALUES +The +.Fn getutxent , +.Fn getutxid , +.Fn getutxline , +and +.Fn getutxuser +functions return a pointer to an +.Vt utmpx +structure that matches the mentioned constraints on success or +.Dv NULL +when reaching the end-of-file or when an error occurs. +.Pp +The +.Fn pututxline +function returns a pointer to an +.Vt utmpx +structure containing a copy of the structure written to disk upon +success. +It returns +.Dv NULL +when the provided +.Vt utmpx +is invalid, or +.Fa ut_type +has a value of +.Dv DEAD_PROCESS +and an entry with an identifier with a value equal to the field +.Fa ut_id +was not found; the global variable +.Va errno +is set to indicate the error. +.Pp +The +.Fn setutxdb +function returns 0 if the user accounting database was opened +successfully. +Otherwise, -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +In addition to the error conditions described in +.Xr open 2 , +.Xr fdopen 3 , +.Xr fopen 3 , +.Xr fseek 3 , +the +.Fn pututxline +function can generate the following errors: +.Bl -tag -width Er +.It Bq Er ESRCH +The value of +.Fa ut_type +is DEAD_PROCESS, and the process entry could not be found. +.It Bq Er EINVAL +The value of +.Fa ut_type +is not supported by this implementation. +.El +In addition to the error conditions described in +.Xr fopen 3 , +the +.Fn setutxdb +function can generate the following errors: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa type +argument contains a value not supported by this implementation. +.It Bq Er EFTYPE +The file format is invalid. +.El +.Sh SEE ALSO +.Xr last 1 , +.Xr write 1 , +.Xr getpid 2 , +.Xr gettimeofday 2 , +.Xr tty 4 , +.Xr ac 8 , +.Xr newsyslog 8 , +.Xr utx 8 +.Sh STANDARDS +The +.Fn endutxent , +.Fn getutxent , +.Fn getutxid , +.Fn getutxline +and +.Fn setutxent +functions are expected to conform to +.St -p1003.1-2008 . +.Pp +The +.Fn pututxline +function deviates from the standard by writing its records to multiple +database files, depending on its +.Fa ut_type . +This prevents the need for special utility functions to update the other +databases, such as the +.Fn updlastlogx +and +.Fn updwtmpx +functions which are available in other implementations. +It also tries to replace +.Dv DEAD_PROCESS +entries in the active sessions database when storing +.Dv USER_PROCESS +entries and no entry with the same value for +.Fa ut_id +has been found. +The standard always requires a new entry to be allocated, which could +cause an unbounded growth of the database. +.Pp +The +.Fn getutxuser +and +.Fn setutxdb +functions, +the +.Fa ut_host +field of the +.Vt utmpx +structure and +.Dv SHUTDOWN_TIME +are extensions. +.Sh HISTORY +These functions appeared in +.Fx 9.0 . +They replaced the +.In utmp.h +interface. +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/getutxent.c b/lib/libc/gen/getutxent.c new file mode 100644 index 000000000000..d0c307538930 --- /dev/null +++ b/lib/libc/gen/getutxent.c @@ -0,0 +1,240 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/endian.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <utmpx.h> +#include "utxdb.h" +#include "un-namespace.h" + +static _Thread_local FILE *uf = NULL; +static _Thread_local int udb; + +int +setutxdb(int db, const char *file) +{ + struct stat sb; + + switch (db) { + case UTXDB_ACTIVE: + if (file == NULL) + file = _PATH_UTX_ACTIVE; + break; + case UTXDB_LASTLOGIN: + if (file == NULL) + file = _PATH_UTX_LASTLOGIN; + break; + case UTXDB_LOG: + if (file == NULL) + file = _PATH_UTX_LOG; + break; + default: + errno = EINVAL; + return (-1); + } + + if (uf != NULL) + fclose(uf); + uf = fopen(file, "re"); + if (uf == NULL) + return (-1); + + if (db != UTXDB_LOG) { + /* Safety check: never use broken files. */ + if (_fstat(fileno(uf), &sb) != -1 && + sb.st_size % sizeof(struct futx) != 0) { + fclose(uf); + uf = NULL; + errno = EFTYPE; + return (-1); + } + /* Prevent reading of partial records. */ + (void)setvbuf(uf, NULL, _IOFBF, + rounddown(BUFSIZ, sizeof(struct futx))); + } + + udb = db; + return (0); +} + +void +setutxent(void) +{ + + setutxdb(UTXDB_ACTIVE, NULL); +} + +void +endutxent(void) +{ + + if (uf != NULL) { + fclose(uf); + uf = NULL; + } +} + +static int +getfutxent(struct futx *fu) +{ + + if (uf == NULL) + setutxent(); + if (uf == NULL) + return (-1); + + if (udb == UTXDB_LOG) { + uint16_t len; + +retry: + if (fread(&len, sizeof(len), 1, uf) != 1) + return (-1); + len = be16toh(len); + if (len == 0) { + /* + * XXX: Though zero-size records are valid in theory, + * they can never occur in practice. Zero-size records + * indicate file corruption. Seek one byte forward, to + * see if we can find a record there. + */ + ungetc('\0', uf); + goto retry; + } + if (len > sizeof *fu) { + /* Forward compatibility. */ + if (fread(fu, sizeof(*fu), 1, uf) != 1) + return (-1); + fseek(uf, len - sizeof(*fu), SEEK_CUR); + } else { + /* Partial record. */ + memset(fu, 0, sizeof(*fu)); + if (fread(fu, len, 1, uf) != 1) + return (-1); + } + } else { + if (fread(fu, sizeof(*fu), 1, uf) != 1) + return (-1); + } + return (0); +} + +struct utmpx * +getutxent(void) +{ + struct futx fu; + + if (getfutxent(&fu) != 0) + return (NULL); + return (futx_to_utx(&fu)); +} + +struct utmpx * +getutxid(const struct utmpx *id) +{ + struct futx fu; + + for (;;) { + if (getfutxent(&fu) != 0) + return (NULL); + + switch (fu.fu_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + case DEAD_PROCESS: + switch (id->ut_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + case DEAD_PROCESS: + if (memcmp(fu.fu_id, id->ut_id, + MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) == + 0) + goto found; + } + break; + default: + if (fu.fu_type == id->ut_type) + goto found; + break; + } + } + +found: + return (futx_to_utx(&fu)); +} + +struct utmpx * +getutxline(const struct utmpx *line) +{ + struct futx fu; + + for (;;) { + if (getfutxent(&fu) != 0) + return (NULL); + + switch (fu.fu_type) { + case USER_PROCESS: + case LOGIN_PROCESS: + if (strncmp(fu.fu_line, line->ut_line, + MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) == + 0) + goto found; + break; + } + } + +found: + return (futx_to_utx(&fu)); +} + +struct utmpx * +getutxuser(const char *user) +{ + struct futx fu; + + for (;;) { + if (getfutxent(&fu) != 0) + return (NULL); + + switch (fu.fu_type) { + case USER_PROCESS: + if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0) + goto found; + break; + } + } + +found: + return (futx_to_utx(&fu)); +} diff --git a/lib/libc/gen/getvfsbyname.3 b/lib/libc/gen/getvfsbyname.3 new file mode 100644 index 000000000000..23036429b27e --- /dev/null +++ b/lib/libc/gen/getvfsbyname.3 @@ -0,0 +1,115 @@ +.\" Copyright (c) 1995 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd August 16, 2018 +.Dt GETVFSBYNAME 3 +.Os +.Sh NAME +.Nm getvfsbyname +.Nd get information about a file system +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/param.h +.In sys/mount.h +.Ft int +.Fn getvfsbyname "const char *name" "struct xvfsconf *vfc" +.Sh DESCRIPTION +The +.Fn getvfsbyname +function provides access to information about a +file system module that is configured in the kernel. +If successful, +the requested file system +.Fa xvfsconf +is returned in the location pointed to by +.Fa vfc . +The fields in a +.Dq Li struct xvfsconf +are defined as follows: +.Pp +.Bl -tag -compact -width vfc_refcount +.It vfc_name +the name of the file system +.It vfc_typenum +the file system type number assigned by the kernel +.It vfc_refcount +the number of active mount points using the file system +.It vfc_flags +flag bits, as described below +.El +.Pp +The flags are defined as follows: +.Pp +.Bl -tag -width VFCF_DELEGADMIN -compact +.It Dv VFCF_STATIC +statically compiled into kernel +.It Dv VFCF_NETWORK +may get data over the network +.It Dv VFCF_READONLY +writes are not implemented +.It Dv VFCF_SYNTHETIC +data does not represent real files +.It Dv VFCF_LOOPBACK +aliases some other mounted FS +.It Dv VFCF_UNICODE +stores file names as Unicode +.It Dv VFCF_JAIL +can be mounted from within a jail if +.Va allow.mount +and +.Va allow.mount.<vfc_name> +jail parameters are set +.It Dv VFCF_DELEGADMIN +supports delegated administration if +.Va vfs.usermount +sysctl is set to +.Dv 1 +.El +.Sh RETURN VALUES +.Rv -std getvfsbyname +.Sh ERRORS +The following errors may be reported: +.Bl -tag -width Er +.It Bq Er ENOENT +The +.Fa name +argument +specifies a file system that is unknown or not configured in the kernel. +.El +.Sh SEE ALSO +.Xr jail 2 , +.Xr mount 2 , +.Xr sysctl 3 , +.Xr jail 8 , +.Xr mount 8 , +.Xr sysctl 8 +.Sh HISTORY +A variant of the +.Fn getvfsbyname +function first appeared in +.Fx 2.0 . diff --git a/lib/libc/gen/getvfsbyname.c b/lib/libc/gen/getvfsbyname.c new file mode 100644 index 000000000000..18cbf64b9f4a --- /dev/null +++ b/lib/libc/gen/getvfsbyname.c @@ -0,0 +1,87 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1995 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/sysctl.h> +#include <errno.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +/* + * fusefs(4) file systems may have a "subtype" which gets appended to + * statfs(2)'s f_fstypename field on a per-mount basis. Allow getvfsbyname to + * match either the full "fusefs.foobar" or the more general "fusefs". + */ +static bool +are_fusefs(const char *fsname, const char *vfc_name) +{ + const static char fusefs[] = "fusefs"; + const static char fusefs_dot[] = "fusefs."; + + return (strncmp(fsname, fusefs_dot, sizeof(fusefs_dot) - 1) == 0 && + strcmp(fusefs, vfc_name) == 0); +} + +/* + * Given a filesystem name, determine if it is resident in the kernel, + * and if it is resident, return its xvfsconf structure. + */ +int +getvfsbyname(const char *fsname, struct xvfsconf *vfcp) +{ + struct xvfsconf *xvfsp; + size_t buflen; + int cnt, i; + + if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0) + return (-1); + xvfsp = malloc(buflen); + if (xvfsp == NULL) + return (-1); + if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) { + free(xvfsp); + return (-1); + } + cnt = buflen / sizeof(struct xvfsconf); + for (i = 0; i < cnt; i++) { + if (strcmp(fsname, xvfsp[i].vfc_name) == 0 || + are_fusefs(fsname, xvfsp[i].vfc_name)) { + memcpy(vfcp, xvfsp + i, sizeof(struct xvfsconf)); + free(xvfsp); + return (0); + } + } + free(xvfsp); + errno = ENOENT; + return (-1); +} diff --git a/lib/libc/gen/glob-compat11.c b/lib/libc/gen/glob-compat11.c new file mode 100644 index 000000000000..cdae52056f61 --- /dev/null +++ b/lib/libc/gen/glob-compat11.c @@ -0,0 +1,1085 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Copyright (c) 2011 The FreeBSD Foundation + * All rights reserved. + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * From: FreeBSD: head/lib/libc/gen/glob.c 317913 2017-05-07 19:52:56Z jilles + */ + +#include <sys/param.h> +#define _WANT_FREEBSD11_STAT +#include <sys/stat.h> + +#include <ctype.h> +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <errno.h> +#include <glob.h> +#include <limits.h> +#include <pwd.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wchar.h> + +#include "collate.h" +#include "gen-compat.h" +#include "glob-compat11.h" + +/* + * glob(3) expansion limits. Stop the expansion if any of these limits + * is reached. This caps the runtime in the face of DoS attacks. See + * also CVE-2010-2632 + */ +#define GLOB_LIMIT_BRACE 128 /* number of brace calls */ +#define GLOB_LIMIT_PATH 65536 /* number of path elements */ +#define GLOB_LIMIT_READDIR 16384 /* number of readdirs */ +#define GLOB_LIMIT_STAT 1024 /* number of stat system calls */ +#define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */ + +struct glob_limit { + size_t l_brace_cnt; + size_t l_path_lim; + size_t l_readdir_cnt; + size_t l_stat_cnt; + size_t l_string_cnt; +}; + +#define DOT L'.' +#define EOS L'\0' +#define LBRACKET L'[' +#define NOT L'!' +#define QUESTION L'?' +#define QUOTE L'\\' +#define RANGE L'-' +#define RBRACKET L']' +#define SEP L'/' +#define STAR L'*' +#define TILDE L'~' +#define LBRACE L'{' +#define RBRACE L'}' +#define COMMA L',' + +#define M_QUOTE 0x8000000000ULL +#define M_PROTECT 0x4000000000ULL +#define M_MASK 0xffffffffffULL +#define M_CHAR 0x00ffffffffULL + +typedef uint_fast64_t Char; + +#define CHAR(c) ((Char)((c)&M_CHAR)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define UNPROT(c) ((c) & ~M_PROTECT) +#define M_ALL META(L'*') +#define M_END META(L']') +#define M_NOT META(L'!') +#define M_ONE META(L'?') +#define M_RNG META(L'-') +#define M_SET META(L'[') +#define ismeta(c) (((c)&M_QUOTE) != 0) +#ifdef DEBUG +#define isprot(c) (((c)&M_PROTECT) != 0) +#endif + +static int compare(const void *, const void *); +static int g_Ctoc(const Char *, char *, size_t); +static int g_lstat(Char *, struct freebsd11_stat *, glob11_t *); +static DIR *g_opendir(Char *, glob11_t *); +static const Char *g_strchr(const Char *, wchar_t); +#ifdef notdef +static Char *g_strcat(Char *, const Char *); +#endif +static int g_stat(Char *, struct freebsd11_stat *, glob11_t *); +static int glob0(const Char *, glob11_t *, struct glob_limit *, + const char *); +static int glob1(Char *, glob11_t *, struct glob_limit *); +static int glob2(Char *, Char *, Char *, Char *, glob11_t *, + struct glob_limit *); +static int glob3(Char *, Char *, Char *, Char *, Char *, glob11_t *, + struct glob_limit *); +static int globextend(const Char *, glob11_t *, struct glob_limit *, + const char *); +static const Char * + globtilde(const Char *, Char *, size_t, glob11_t *); +static int globexp0(const Char *, glob11_t *, struct glob_limit *, + const char *); +static int globexp1(const Char *, glob11_t *, struct glob_limit *); +static int globexp2(const Char *, const Char *, glob11_t *, + struct glob_limit *); +static int globfinal(glob11_t *, struct glob_limit *, size_t, + const char *); +static int match(Char *, Char *, Char *); +static int err_nomatch(glob11_t *, struct glob_limit *, const char *); +static int err_aborted(glob11_t *, int, char *); +#ifdef DEBUG +static void qprintf(const char *, Char *); +#endif + +int +freebsd11_glob(const char * __restrict pattern, int flags, + int (*errfunc)(const char *, int), glob11_t * __restrict pglob) +{ + struct glob_limit limit = { 0, 0, 0, 0, 0 }; + const char *patnext; + Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot; + mbstate_t mbs; + wchar_t wc; + size_t clen; + int too_long; + + patnext = pattern; + if (!(flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + if (flags & GLOB_LIMIT) { + limit.l_path_lim = pglob->gl_matchc; + if (limit.l_path_lim == 0) + limit.l_path_lim = GLOB_LIMIT_PATH; + } + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_errfunc = errfunc; + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN - 1; + too_long = 1; + if (flags & GLOB_NOESCAPE) { + memset(&mbs, 0, sizeof(mbs)); + while (bufnext <= bufend) { + clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) + return (err_nomatch(pglob, &limit, pattern)); + else if (clen == 0) { + too_long = 0; + break; + } + *bufnext++ = wc; + patnext += clen; + } + } else { + /* Protect the quoted characters. */ + memset(&mbs, 0, sizeof(mbs)); + while (bufnext <= bufend) { + if (*patnext == '\\') { + if (*++patnext == '\0') { + *bufnext++ = QUOTE; + continue; + } + prot = M_PROTECT; + } else + prot = 0; + clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) + return (err_nomatch(pglob, &limit, pattern)); + else if (clen == 0) { + too_long = 0; + break; + } + *bufnext++ = wc | prot; + patnext += clen; + } + } + if (too_long) + return (err_nomatch(pglob, &limit, pattern)); + *bufnext = EOS; + + if (flags & GLOB_BRACE) + return (globexp0(patbuf, pglob, &limit, pattern)); + else + return (glob0(patbuf, pglob, &limit, pattern)); +} + +static int +globexp0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit, + const char *origpat) { + int rv; + size_t oldpathc; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (glob0(pattern, pglob, limit, origpat)); + } + + oldpathc = pglob->gl_pathc; + + if ((rv = globexp1(pattern, pglob, limit)) != 0) + return rv; + + return (globfinal(pglob, limit, oldpathc, origpat)); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int +globexp1(const Char *pattern, glob11_t *pglob, struct glob_limit *limit) +{ + const Char* ptr; + + if ((ptr = g_strchr(pattern, LBRACE)) != NULL) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (globexp2(ptr, pattern, pglob, limit)); + } + + return (glob0(pattern, pglob, limit, NULL)); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int +globexp2(const Char *ptr, const Char *pattern, glob11_t *pglob, + struct glob_limit *limit) +{ + int i, rv; + Char *lm, *ls; + const Char *pe, *pm, *pm1, *pl; + Char patbuf[MAXPATHLEN]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + *lm = EOS; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe != EOS; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) + return (glob0(pattern, pglob, limit, NULL)); + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pm1; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + rv = globexp1(patbuf, pglob, limit); + if (rv) + return (rv); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + return (0); +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob11_t *pglob) +{ + struct passwd *pwd; + char *h, *sc; + const Char *p; + Char *b, *eb; + wchar_t wc; + wchar_t wbuf[MAXPATHLEN]; + wchar_t *wbufend, *dc; + size_t clen; + mbstate_t mbs; + int too_long; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return (pattern); + + /* + * Copy up to the end of the string or / + */ + eb = &patbuf[patbuf_len - 1]; + for (p = pattern + 1, b = patbuf; + b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++) + continue; + + if (*p != EOS && UNPROT(*p) != SEP) + return (NULL); + + *b = EOS; + h = NULL; + + if (patbuf[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME first (iff + * we're not running setuid or setgid) and then trying + * the password file + */ + if ((h = secure_getenv("HOME")) == NULL) { + if (((h = getlogin()) != NULL && + (pwd = getpwnam(h)) != NULL) || + (pwd = getpwuid(getuid())) != NULL) + h = pwd->pw_dir; + else + return (pattern); + } + } + else { + /* + * Expand a ~user + */ + if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf))) + return (NULL); + if ((pwd = getpwnam((char *)wbuf)) == NULL) + return (pattern); + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + dc = wbuf; + sc = h; + wbufend = wbuf + MAXPATHLEN - 1; + too_long = 1; + memset(&mbs, 0, sizeof(mbs)); + while (dc <= wbufend) { + clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) { + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if ((*dc++ = wc) == EOS) { + too_long = 0; + break; + } + sc += clen; + } + if (too_long) + return (NULL); + + dc = wbuf; + for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT) + continue; + if (*dc != EOS) + return (NULL); + + /* Append the rest of the pattern */ + if (*p != EOS) { + too_long = 1; + while (b <= eb) { + if ((*b++ = *p++) == EOS) { + too_long = 0; + break; + } + } + if (too_long) + return (NULL); + } else + *b = EOS; + + return (patbuf); +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. + */ +static int +glob0(const Char *pattern, glob11_t *pglob, struct glob_limit *limit, + const char *origpat) { + const Char *qpatnext; + int err; + size_t oldpathc; + Char *bufnext, c, patbuf[MAXPATHLEN]; + + qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); + if (qpatnext == NULL) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr(qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to avoid exponential behavior + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, pglob, limit)) != 0) + return(err); + + if (origpat != NULL) + return (globfinal(pglob, limit, oldpathc, origpat)); + + return (0); +} + +static int +globfinal(glob11_t *pglob, struct glob_limit *limit, size_t oldpathc, + const char *origpat) { + if (pglob->gl_pathc == oldpathc) + return (err_nomatch(pglob, limit, origpat)); + + if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + + return (0); +} + +static int +compare(const void *p, const void *q) +{ + return (strcoll(*(char **)p, *(char **)q)); +} + +static int +glob1(Char *pattern, glob11_t *pglob, struct glob_limit *limit) +{ + Char pathbuf[MAXPATHLEN]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return (0); + return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1, + pattern, pglob, limit)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, + glob11_t *pglob, struct glob_limit *limit) +{ + struct freebsd11_stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return (0); + + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + if ((pglob->gl_flags & GLOB_MARK) && + UNPROT(pathend[-1]) != SEP && + (S_ISDIR(sb.st_mode) || + (S_ISLNK(sb.st_mode) && + g_stat(pathbuf, &sb, pglob) == 0 && + S_ISDIR(sb.st_mode)))) { + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return (globextend(pathbuf, pglob, limit, NULL)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && UNPROT(*p) != SEP) { + if (ismeta(*p)) + anymeta = 1; + if (q + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (UNPROT(*pattern) == SEP) { + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend++ = *pattern++; + } + } else /* Need expansion, recurse. */ + return (glob3(pathbuf, pathend, pathend_last, pattern, + p, pglob, limit)); + } + /* NOTREACHED */ +} + +static int +glob3(Char *pathbuf, Char *pathend, Char *pathend_last, + Char *pattern, Char *restpattern, + glob11_t *pglob, struct glob_limit *limit) +{ + struct freebsd11_dirent *dp; + DIR *dirp; + int err, too_long, saverrno, saverrno2; + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + struct freebsd11_dirent *(*readdirfunc)(DIR *); + + if (pathend > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend = EOS; + if (pglob->gl_errfunc != NULL && + g_Ctoc(pathbuf, buf, sizeof(buf))) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + + saverrno = errno; + errno = 0; + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + if (errno == ENOENT || errno == ENOTDIR) + return (0); + err = err_aborted(pglob, errno, buf); + if (errno == 0) + errno = saverrno; + return (err); + } + + err = 0; + + /* pglob->gl_readdir takes a void *, fix this manually */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = + (struct freebsd11_dirent *(*)(DIR *))pglob->gl_readdir; + else + readdirfunc = freebsd11_readdir; + + errno = 0; + /* Search directory for matching names. */ + while ((dp = (*readdirfunc)(dirp)) != NULL) { + char *sc; + Char *dc; + wchar_t wc; + size_t clen; + mbstate_t mbs; + + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) { + errno = E2BIG; + err = GLOB_NOSPACE; + break; + } + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) { + errno = 0; + continue; + } + memset(&mbs, 0, sizeof(mbs)); + dc = pathend; + sc = dp->d_name; + too_long = 1; + while (dc <= pathend_last) { + clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) { + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if ((*dc++ = wc) == EOS) { + too_long = 0; + break; + } + sc += clen; + } + if (too_long && (err = err_aborted(pglob, ENAMETOOLONG, + buf))) { + errno = ENAMETOOLONG; + break; + } + if (too_long || !match(pathend, pattern, restpattern)) { + *pathend = EOS; + errno = 0; + continue; + } + if (errno == 0) + errno = saverrno; + err = glob2(pathbuf, --dc, pathend_last, restpattern, + pglob, limit); + if (err) + break; + errno = 0; + } + + saverrno2 = errno; + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + errno = saverrno2; + + if (err) + return (err); + + if (dp == NULL && errno != 0 && + (err = err_aborted(pglob, errno, buf))) + return (err); + + if (errno == 0) + errno = saverrno; + return (0); +} + + +/* + * Extend the gl_pathv member of a glob11_t structure to accommodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob11_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(const Char *path, glob11_t *pglob, struct glob_limit *limit, + const char *origpat) +{ + char **pathv; + size_t i, newn, len; + char *copy; + const Char *p; + + if ((pglob->gl_flags & GLOB_LIMIT) && + pglob->gl_matchc > limit->l_path_lim) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + + newn = 2 + pglob->gl_pathc + pglob->gl_offs; + /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */ + pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv)); + if (pathv == NULL) + return (GLOB_NOSPACE); + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs + 1; --i > 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + if (origpat != NULL) + copy = strdup(origpat); + else { + for (p = path; *p++ != EOS;) + continue; + len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ + if ((copy = malloc(len)) != NULL) { + if (g_Ctoc(path, copy, len)) { + free(copy); + errno = E2BIG; + return (GLOB_NOSPACE); + } + } + } + if (copy != NULL) { + limit->l_string_cnt += strlen(copy) + 1; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_string_cnt >= GLOB_LIMIT_STRING) { + free(copy); + errno = E2BIG; + return (GLOB_NOSPACE); + } + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + return (copy == NULL ? GLOB_NOSPACE : 0); +} + +/* + * pattern matching function for filenames. + */ +static int +match(Char *name, Char *pat, Char *patend) +{ + int ok, negate_range; + Char c, k, *nextp, *nextn; + struct xlocale_collate *table = + (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; + + nextn = NULL; + nextp = NULL; + + while (1) { + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return (1); + if (*name == EOS) + return (0); + nextn = name + 1; + nextp = pat - 1; + break; + case M_ONE: + if (*name++ == EOS) + goto fail; + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + goto fail; + negate_range = ((*pat & M_MASK) == M_NOT); + if (negate_range != 0) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (table->__collate_load_error ? + CHAR(c) <= CHAR(k) && + CHAR(k) <= CHAR(pat[1]) : + __wcollate_range_cmp(CHAR(c), + CHAR(k)) <= 0 && + __wcollate_range_cmp(CHAR(k), + CHAR(pat[1])) <= 0) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + goto fail; + break; + default: + if (*name++ != c) + goto fail; + break; + } + } + if (*name == EOS) + return (1); + + fail: + if (nextn == NULL) + break; + pat = nextp; + name = nextn; + } + return (0); +} + +/* Free allocated data belonging to a glob11_t structure. */ +void +freebsd11_globfree(glob11_t *pglob) +{ + size_t i; + char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} + +static DIR * +g_opendir(Char *str, glob11_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (*str == EOS) + strcpy(buf, "."); + else { + if (g_Ctoc(str, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (NULL); + } + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return ((*pglob->gl_opendir)(buf)); + + return (opendir(buf)); +} + +static int +g_lstat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (g_Ctoc(fn, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (-1); + } + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return (freebsd11_lstat(buf, sb)); +} + +static int +g_stat(Char *fn, struct freebsd11_stat *sb, glob11_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (g_Ctoc(fn, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (-1); + } + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return ((*pglob->gl_stat)(buf, sb)); + return (freebsd11_stat(buf, sb)); +} + +static const Char * +g_strchr(const Char *str, wchar_t ch) +{ + + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +static int +g_Ctoc(const Char *str, char *buf, size_t len) +{ + mbstate_t mbs; + size_t clen; + + memset(&mbs, 0, sizeof(mbs)); + while (len >= MB_CUR_MAX) { + clen = wcrtomb(buf, CHAR(*str), &mbs); + if (clen == (size_t)-1) { + /* XXX See initial comment #2. */ + *buf = (char)CHAR(*str); + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if (CHAR(*str) == EOS) + return (0); + str++; + buf += clen; + len -= clen; + } + return (1); +} + +static int +err_nomatch(glob11_t *pglob, struct glob_limit *limit, const char *origpat) { + /* + * If there was no match we are going to append the origpat + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the origpat did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR))) + return (globextend(NULL, pglob, limit, origpat)); + return (GLOB_NOMATCH); +} + +static int +err_aborted(glob11_t *pglob, int err, char *buf) { + if ((pglob->gl_errfunc != NULL && pglob->gl_errfunc(buf, err)) || + (pglob->gl_flags & GLOB_ERR)) + return (GLOB_ABORTED); + return (0); +} + +#ifdef DEBUG +static void +qprintf(const char *str, Char *s) +{ + Char *p; + + (void)printf("%s\n", str); + if (s != NULL) { + for (p = s; *p != EOS; p++) + (void)printf("%c", (char)CHAR(*p)); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (isprot(*p) ? '\\' : ' ')); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (ismeta(*p) ? '_' : ' ')); + (void)printf("\n"); + } +} +#endif + +__sym_compat(glob, freebsd11_glob, FBSD_1.0); +__sym_compat(globfree, freebsd11_globfree, FBSD_1.0); diff --git a/lib/libc/gen/glob-compat11.h b/lib/libc/gen/glob-compat11.h new file mode 100644 index 000000000000..713e1a454b7f --- /dev/null +++ b/lib/libc/gen/glob-compat11.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _GLOB_COMPAT11_H_ +#define _GLOB_COMPAT11_H_ + +#include <sys/types.h> +#include <glob.h> + +struct freebsd11_stat; +typedef struct { + size_t gl_pathc; /* Count of total paths so far. */ + size_t gl_matchc; /* Count of paths matching pattern. */ + size_t gl_offs; /* Reserved at beginning of gl_pathv. */ + int gl_flags; /* Copy of flags parameter to glob. */ + char **gl_pathv; /* List of paths matching pattern. */ + /* Copy of errfunc parameter to glob. */ + int (*gl_errfunc)(const char *, int); + + /* + * Alternate filesystem access methods for glob; replacement + * versions of closedir(3), readdir(3), opendir(3), stat(2) + * and lstat(2). + */ + void (*gl_closedir)(void *); + struct freebsd11_dirent *(*gl_readdir)(void *); + void *(*gl_opendir)(const char *); + int (*gl_lstat)(const char *, struct freebsd11_stat *); + int (*gl_stat)(const char *, struct freebsd11_stat *); +} glob11_t; + +__BEGIN_DECLS +int freebsd11_glob(const char * __restrict, int, + int (*)(const char *, int), glob11_t * __restrict); +void freebsd11_globfree(glob11_t *); +__END_DECLS + +#endif /* !_GLOB_COMPAT11_H_ */ diff --git a/lib/libc/gen/glob.3 b/lib/libc/gen/glob.3 new file mode 100644 index 000000000000..839d98ce02b5 --- /dev/null +++ b/lib/libc/gen/glob.3 @@ -0,0 +1,502 @@ +.\" Copyright (c) 1989, 1991, 1993, 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" Guido van Rossum. +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 23, 2025 +.Dt GLOB 3 +.Os +.Sh NAME +.Nm glob , +.Nm glob_b , +.Nm globfree +.Nd generate pathnames matching a pattern +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In glob.h +.Ft int +.Fn glob "const char * restrict pattern" "int flags" "int (*errfunc)(const char *epath, int errno)" "glob_t * restrict pglob" +.Ft int +.Fn glob_b "const char * restrict pattern" "int flags" "int (^errblk)(const char *epath, int errno)" "glob_t * restrict pglob" +.Ft void +.Fn globfree "glob_t *pglob" +.Sh DESCRIPTION +The +.Fn glob +function +is a pathname generator that implements the rules for file name pattern +matching used by the shell. +.Pp +The include file +.In glob.h +defines the structure type +.Fa glob_t , +which contains at least the following fields: +.Bd -literal +typedef struct { + size_t gl_pathc; /* count of total paths so far */ + size_t gl_matchc; /* count of paths matching pattern */ + size_t gl_offs; /* reserved at beginning of gl_pathv */ + int gl_flags; /* returned flags */ + char **gl_pathv; /* list of paths matching pattern */ +} glob_t; +.Ed +.Pp +The argument +.Fa pattern +is a pointer to a pathname pattern to be expanded. +The +.Fn glob +argument +matches all accessible pathnames against the pattern and creates +a list of the pathnames that match. +In order to have access to a pathname, +.Fn glob +requires search permission on every component of a path except the last +and read permission on each directory of any filename component of +.Fa pattern +that contains any of the special characters +.Ql * , +.Ql ?\& +or +.Ql \&[ . +.Pp +The +.Fn glob +argument +stores the number of matched pathnames into the +.Fa gl_pathc +field, and a pointer to a list of pointers to pathnames into the +.Fa gl_pathv +field. +The first pointer after the last pathname is +.Dv NULL . +If the pattern does not match any pathnames, the returned number of +matched paths is set to zero. +.Pp +It is the caller's responsibility to create the structure pointed to by +.Fa pglob . +The +.Fn glob +function allocates other space as needed, including the memory pointed +to by +.Fa gl_pathv . +.Pp +The argument +.Fa flags +is used to modify the behavior of +.Fn glob . +The value of +.Fa flags +is the bitwise inclusive +.Tn OR +of any of the following +values defined in +.In glob.h : +.Bl -tag -width GLOB_ALTDIRFUNC +.It Dv GLOB_APPEND +Append pathnames generated to the ones from a previous call (or calls) +to +.Fn glob . +The value of +.Fa gl_pathc +will be the total matches found by this call and the previous call(s). +The pathnames are appended to, not merged with the pathnames returned by +the previous call(s). +Between calls, the caller must not change the setting of the +.Dv GLOB_DOOFFS +flag, nor change the value of +.Fa gl_offs +when +.Dv GLOB_DOOFFS +is set, nor (obviously) call +.Fn globfree +for +.Fa pglob . +.It Dv GLOB_DOOFFS +Make use of the +.Fa gl_offs +field. +If this flag is set, +.Fa gl_offs +is used to specify how many +.Dv NULL +pointers to prepend to the beginning +of the +.Fa gl_pathv +field. +In other words, +.Fa gl_pathv +will point to +.Fa gl_offs +.Dv NULL +pointers, +followed by +.Fa gl_pathc +pathname pointers, followed by a +.Dv NULL +pointer. +.It Dv GLOB_ERR +Causes +.Fn glob +to return when it encounters a directory that it cannot open or read. +Ordinarily, +.Fn glob +continues to find matches. +.It Dv GLOB_MARK +Each pathname that is a directory that matches +.Fa pattern +has a slash +appended. +.It Dv GLOB_NOCHECK +If +.Fa pattern +does not match any pathname, then +.Fn glob +returns a list +consisting of only +.Fa pattern , +with the number of total pathnames set to 1, and the number of matched +pathnames set to 0. +The effect of backslash escaping is present in the pattern returned. +.It Dv GLOB_NOESCAPE +By default, a backslash +.Pq Ql \e +character is used to escape the following character in the pattern, +avoiding any special interpretation of the character. +If +.Dv GLOB_NOESCAPE +is set, backslash escaping is disabled. +.It Dv GLOB_NOSORT +By default, the pathnames are sorted in ascending +collation +order; +this flag prevents that sorting (speeding up +.Fn glob ) . +.El +.Pp +The following values may also be included in +.Fa flags , +however, they are non-standard extensions to +.St -p1003.2 . +.Bl -tag -width GLOB_ALTDIRFUNC +.It Dv GLOB_ALTDIRFUNC +The following additional fields in the pglob structure have been +initialized with alternate functions for glob to use to open, read, +and close directories and to get stat information on names found +in those directories. +.Bd -literal +void *(*gl_opendir)(const char * name); +struct dirent *(*gl_readdir)(void *); +void (*gl_closedir)(void *); +int (*gl_lstat)(const char *name, struct stat *st); +int (*gl_stat)(const char *name, struct stat *st); +.Ed +.Pp +This extension is provided to allow programs such as +.Xr restore 8 +to provide globbing from directories stored on tape. +.It Dv GLOB_BRACE +Pre-process the pattern string to expand +.Ql {pat,pat,...} +strings like +.Xr csh 1 . +The pattern +.Ql {} +is left unexpanded for historical reasons (and +.Xr csh 1 +does the same thing to +ease typing +of +.Xr find 1 +patterns). +.It Dv GLOB_MAGCHAR +Set by the +.Fn glob +function if the pattern included globbing characters. +See the description of the usage of the +.Fa gl_matchc +structure member for more details. +.It Dv GLOB_NOMAGIC +Is the same as +.Dv GLOB_NOCHECK +but it only appends the +.Fa pattern +if it does not contain any of the special characters ``*'', ``?'' or ``[''. +.Dv GLOB_NOMAGIC +is provided to simplify implementing the historic +.Xr csh 1 +globbing behavior and should probably not be used anywhere else. +.It Dv GLOB_TILDE +Expand patterns that start with +.Ql ~ +to user name home directories. +.It Dv GLOB_LIMIT +Limit the total number of returned pathnames to the value provided in +.Fa gl_matchc +(default +.Dv ARG_MAX ) . +This option should be set for programs +that can be coerced into a denial of service attack +via patterns that expand to a very large number of matches, +such as a long string of +.Ql */../*/.. . +.El +.Pp +If, during the search, a directory is encountered that cannot be opened +or read and +.Fa errfunc +is +.Pf non- Dv NULL , +.Fn glob +calls +.Fa \*(lp*errfunc\*(rp Ns ( Fa path , errno ) . +This may be unintuitive: a pattern like +.Ql */Makefile +will try to +.Xr stat 2 +.Ql foo/Makefile +even if +.Ql foo +is not a directory, resulting in a +call to +.Fa errfunc . +The error routine can suppress this action by testing for +.Er ENOENT +and +.Er ENOTDIR ; +however, the +.Dv GLOB_ERR +flag will still cause an immediate +return when this happens. +.Pp +If +.Fa errfunc +returns non-zero, +.Fn glob +stops the scan and returns +.Dv GLOB_ABORTED +after setting +.Fa gl_pathc +and +.Fa gl_pathv +to reflect any paths already matched. +This also happens if an error is encountered and +.Dv GLOB_ERR +is set in +.Fa flags , +regardless of the return value of +.Fa errfunc , +if called. +If +.Dv GLOB_ERR +is not set and either +.Fa errfunc +is +.Dv NULL +or +.Fa errfunc +returns zero, the error is ignored. +.Pp +The +.Fn glob_b +function is like +.Fn glob +except that the error callback is a block pointer instead of a function +pointer. +.Pp +The +.Fn globfree +function frees any space associated with +.Fa pglob +from a previous call(s) to +.Fn glob +or +.Fn glob_b . +.Sh RETURN VALUES +On successful completion, +.Fn glob +and +.Fn glob_b +return zero. +In addition, the fields of +.Fa pglob +contain the values described below: +.Bl -tag -width GLOB_NOCHECK +.It Fa gl_pathc +contains the total number of matched pathnames so far. +This includes other matches from previous invocations of +.Fn glob +or +.Fn glob_b +if +.Dv GLOB_APPEND +was specified. +.It Fa gl_matchc +contains the number of matched pathnames in the current invocation of +.Fn glob +or +.Fn glob_b . +.It Fa gl_flags +contains a copy of the +.Fa flags +argument with the bit +.Dv GLOB_MAGCHAR +set if +.Fa pattern +contained any of the special characters ``*'', ``?'' or ``['', cleared +if not. +.It Fa gl_pathv +contains a pointer to a +.Dv NULL Ns -terminated +list of matched pathnames. +However, if +.Fa gl_pathc +is zero, the contents of +.Fa gl_pathv +are undefined. +.El +.Pp +If +.Fn glob +or +.Fn glob_b +terminates due to an error, it sets errno and returns one of the +following non-zero constants, which are defined in the include +file +.In glob.h : +.Bl -tag -width GLOB_NOCHECK +.It Dv GLOB_NOSPACE +An attempt to allocate memory failed, or if +.Fa errno +was E2BIG, +.Dv GLOB_LIMIT +was specified in the flags and +.Fa pglob\->gl_matchc +or more patterns were matched. +.It Dv GLOB_ABORTED +The scan was stopped because an error was encountered and either +.Dv GLOB_ERR +was set or +.Fa \*(lp*errfunc\*(rp\*(lp\*(rp +returned non-zero. +.It Dv GLOB_NOMATCH +The pattern did not match a pathname and +.Dv GLOB_NOCHECK +was not set. +.El +.Pp +The arguments +.Fa pglob\->gl_pathc +and +.Fa pglob\->gl_pathv +are still set as specified above. +.Sh EXAMPLES +A rough equivalent of +.Ql "ls -l *.c *.h" +can be obtained with the +following code: +.Bd -literal -offset indent +glob_t g; + +g.gl_offs = 2; +glob("*.c", GLOB_DOOFFS, NULL, &g); +glob("*.h", GLOB_DOOFFS | GLOB_APPEND, NULL, &g); +g.gl_pathv[0] = "ls"; +g.gl_pathv[1] = "-l"; +execvp("ls", g.gl_pathv); +.Ed +.Sh CAVEATS +The +.Fn glob +and +.Fn glob_b +functions +will not match filenames that begin with a period +unless this is specifically requested (e.g., by ".*"). +.Sh SEE ALSO +.Xr sh 1 , +.Xr fnmatch 3 , +.Xr regex 3 +.Sh STANDARDS +The current implementation of the +.Fn glob +function +.Em does not +conform to +.St -p1003.2 . +Collating symbol expressions, equivalence class expressions and +character class expressions are not supported. +.Pp +The flags +.Dv GLOB_ALTDIRFUNC , +.Dv GLOB_BRACE , +.Dv GLOB_LIMIT , +.Dv GLOB_MAGCHAR , +.Dv GLOB_NOMAGIC , +and +.Dv GLOB_TILDE , +and the fields +.Fa gl_matchc +and +.Fa gl_flags +are extensions to the +.Tn POSIX +standard and +should not be used by applications striving for strict +conformance. +.Sh HISTORY +The +.Fn glob +and +.Fn globfree +functions first appeared in +.Bx 4.4 . +The +.Fn glob_b +function first appeared in +.Fx 15.0 . +.Sh BUGS +Patterns longer than +.Dv MAXPATHLEN +may cause unchecked errors. +.Pp +The +.Fn glob +and +.Fn glob_b +functions +may fail and set errno for any of the errors specified for the +library routines +.Xr stat 2 , +.Xr closedir 3 , +.Xr opendir 3 , +.Xr readdir 3 , +.Xr malloc 3 , +and +.Xr free 3 . diff --git a/lib/libc/gen/glob.c b/lib/libc/gen/glob.c new file mode 100644 index 000000000000..f7da5f0cda09 --- /dev/null +++ b/lib/libc/gen/glob.c @@ -0,0 +1,1155 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Guido van Rossum. + * + * Copyright (c) 2011 The FreeBSD Foundation + * + * Portions of this software were developed by David Chisnall + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * glob(3) -- a superset of the one defined in POSIX 1003.2. + * + * The [!...] convention to negate a range is supported (SysV, Posix, ksh). + * + * Optional extra services, controlled by flags not defined by POSIX: + * + * GLOB_QUOTE: + * Escaping convention: \ inhibits any special meaning the following + * character might have (except \ at end of string is retained). + * GLOB_MAGCHAR: + * Set in gl_flags if pattern contained a globbing character. + * GLOB_NOMAGIC: + * Same as GLOB_NOCHECK, but it will only append pattern if it did + * not contain any magic characters. [Used in csh style globbing] + * GLOB_ALTDIRFUNC: + * Use alternately specified directory access functions. + * GLOB_TILDE: + * expand ~user/foo to the /home/dir/of/user/foo + * GLOB_BRACE: + * expand {1,2}{a,b} to 1a 1b 2a 2b + * gl_matchc: + * Number of matches in the current invocation of glob. + */ + +/* + * Some notes on multibyte character support: + * 1. Patterns with illegal byte sequences match nothing - even if + * GLOB_NOCHECK is specified. + * 2. Illegal byte sequences in filenames are handled by treating them as + * single-byte characters with a values of such bytes of the sequence + * cast to wchar_t. + * 3. State-dependent encodings are not currently supported. + */ + +#include <sys/param.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <glob.h> +#include <limits.h> +#include <pwd.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wchar.h> + +#include "block_abi.h" +#include "collate.h" + +typedef DECLARE_BLOCK(int, glob_b_block, const char*, int); + +/* + * glob(3) expansion limits. Stop the expansion if any of these limits + * is reached. This caps the runtime in the face of DoS attacks. See + * also CVE-2010-2632 + */ +#define GLOB_LIMIT_BRACE 128 /* number of brace calls */ +#define GLOB_LIMIT_PATH 65536 /* number of path elements */ +#define GLOB_LIMIT_READDIR 16384 /* number of readdirs */ +#define GLOB_LIMIT_STAT 1024 /* number of stat system calls */ +#define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */ + +struct glob_limit { + size_t l_brace_cnt; + size_t l_path_lim; + size_t l_readdir_cnt; + size_t l_stat_cnt; + size_t l_string_cnt; +}; + +#define DOT L'.' +#define EOS L'\0' +#define LBRACKET L'[' +#define NOT L'!' +#define QUESTION L'?' +#define QUOTE L'\\' +#define RANGE L'-' +#define RBRACKET L']' +#define SEP L'/' +#define STAR L'*' +#define TILDE L'~' +#define LBRACE L'{' +#define RBRACE L'}' +#define COMMA L',' + +#define M_QUOTE 0x8000000000ULL +#define M_PROTECT 0x4000000000ULL +#define M_MASK 0xffffffffffULL +#define M_CHAR 0x00ffffffffULL + +typedef uint_fast64_t Char; + +#define CHAR(c) ((Char)((c)&M_CHAR)) +#define META(c) ((Char)((c)|M_QUOTE)) +#define UNPROT(c) ((c) & ~M_PROTECT) +#define M_ALL META(L'*') +#define M_END META(L']') +#define M_NOT META(L'!') +#define M_ONE META(L'?') +#define M_RNG META(L'-') +#define M_SET META(L'[') +#define ismeta(c) (((c)&M_QUOTE) != 0) +#ifdef DEBUG +#define isprot(c) (((c)&M_PROTECT) != 0) +#endif + +static int compare(const void *, const void *); +static int g_Ctoc(const Char *, char *, size_t); +static int g_lstat(Char *, struct stat *, glob_t *); +static DIR *g_opendir(Char *, glob_t *); +static const Char *g_strchr(const Char *, wchar_t); +#ifdef notdef +static Char *g_strcat(Char *, const Char *); +#endif +static int g_stat(Char *, struct stat *, glob_t *); +static int glob0(const Char *, glob_t *, struct glob_limit *, + const char *); +static int glob1(Char *, glob_t *, struct glob_limit *); +static int glob2(Char *, Char *, Char *, Char *, glob_t *, + struct glob_limit *); +static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, + struct glob_limit *); +static int globextend(const Char *, glob_t *, struct glob_limit *, + const char *); +static const Char * + globtilde(const Char *, Char *, size_t, glob_t *); +static int globexp0(const Char *, glob_t *, struct glob_limit *, + const char *); +static int globexp1(const Char *, glob_t *, struct glob_limit *); +static int globexp2(const Char *, const Char *, glob_t *, + struct glob_limit *); +static int globfinal(glob_t *, struct glob_limit *, size_t, + const char *); +static int match(Char *, Char *, Char *); +static int err_nomatch(glob_t *, struct glob_limit *, const char *); +static int err_aborted(glob_t *, int, char *); +#ifdef DEBUG +static void qprintf(const char *, Char *); +#endif + +static int +__glob(const char *pattern, glob_t *pglob) +{ + struct glob_limit limit = { 0, 0, 0, 0, 0 }; + const char *patnext; + Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot; + mbstate_t mbs; + wchar_t wc; + size_t clen; + int too_long; + + patnext = pattern; + if (!(pglob->gl_flags & GLOB_APPEND)) { + pglob->gl_pathc = 0; + pglob->gl_pathv = NULL; + if (!(pglob->gl_flags & GLOB_DOOFFS)) + pglob->gl_offs = 0; + } + if (pglob->gl_flags & GLOB_LIMIT) { + limit.l_path_lim = pglob->gl_matchc; + if (limit.l_path_lim == 0) + limit.l_path_lim = GLOB_LIMIT_PATH; + } + pglob->gl_matchc = 0; + + bufnext = patbuf; + bufend = bufnext + MAXPATHLEN - 1; + too_long = 1; + if (pglob->gl_flags & GLOB_NOESCAPE) { + memset(&mbs, 0, sizeof(mbs)); + while (bufnext <= bufend) { + clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) + return (err_nomatch(pglob, &limit, pattern)); + else if (clen == 0) { + too_long = 0; + break; + } + *bufnext++ = wc; + patnext += clen; + } + } else { + /* Protect the quoted characters. */ + memset(&mbs, 0, sizeof(mbs)); + while (bufnext <= bufend) { + if (*patnext == '\\') { + if (*++patnext == '\0') { + *bufnext++ = QUOTE; + continue; + } + prot = M_PROTECT; + } else + prot = 0; + clen = mbrtowc(&wc, patnext, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) + return (err_nomatch(pglob, &limit, pattern)); + else if (clen == 0) { + too_long = 0; + break; + } + *bufnext++ = wc | prot; + patnext += clen; + } + } + if (too_long) + return (err_nomatch(pglob, &limit, pattern)); + *bufnext = EOS; + + if (pglob->gl_flags & GLOB_BRACE) + return (globexp0(patbuf, pglob, &limit, pattern)); + else + return (glob0(patbuf, pglob, &limit, pattern)); +} + +int +glob(const char * __restrict pattern, int flags, + int (*errfunc)(const char *, int), glob_t * __restrict pglob) +{ + int rv; + + pglob->gl_flags = flags & ~(GLOB_MAGCHAR | _GLOB_ERR_BLOCK); + pglob->gl_errfunc = errfunc; + rv = __glob(pattern, pglob); + pglob->gl_errfunc = NULL; + + return (rv); +} + +int +glob_b(const char * __restrict pattern, int flags, + glob_b_block block, glob_t * __restrict pglob) +{ + int rv; + + pglob->gl_flags = flags & ~GLOB_MAGCHAR; + pglob->gl_flags |= _GLOB_ERR_BLOCK; + pglob->gl_errblk = block; + rv = __glob(pattern, pglob); + pglob->gl_errblk = NULL; + + return (rv); +} + +static int +globexp0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, + const char *origpat) +{ + int rv; + size_t oldpathc; + + /* Protect a single {}, for find(1), like csh */ + if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (glob0(pattern, pglob, limit, origpat)); + } + + oldpathc = pglob->gl_pathc; + + if ((rv = globexp1(pattern, pglob, limit)) != 0) + return rv; + + return (globfinal(pglob, limit, oldpathc, origpat)); +} + +/* + * Expand recursively a glob {} pattern. When there is no more expansion + * invoke the standard globbing routine to glob the rest of the magic + * characters + */ +static int +globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit) +{ + const Char* ptr; + + if ((ptr = g_strchr(pattern, LBRACE)) != NULL) { + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + return (globexp2(ptr, pattern, pglob, limit)); + } + + return (glob0(pattern, pglob, limit, NULL)); +} + + +/* + * Recursive brace globbing helper. Tries to expand a single brace. + * If it succeeds then it invokes globexp1 with the new pattern. + * If it fails then it tries to glob the rest of the pattern and returns. + */ +static int +globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, + struct glob_limit *limit) +{ + int i, rv; + Char *lm, *ls; + const Char *pe, *pm, *pm1, *pl; + Char patbuf[MAXPATHLEN]; + + /* copy part up to the brace */ + for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++) + continue; + *lm = EOS; + ls = lm; + + /* Find the balanced brace */ + for (i = 0, pe = ++ptr; *pe != EOS; pe++) + if (*pe == LBRACKET) { + /* Ignore everything between [] */ + for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++) + continue; + if (*pe == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pe = pm; + } + } + else if (*pe == LBRACE) + i++; + else if (*pe == RBRACE) { + if (i == 0) + break; + i--; + } + + /* Non matching braces; just glob the pattern */ + if (i != 0 || *pe == EOS) + return (glob0(pattern, pglob, limit, NULL)); + + for (i = 0, pl = pm = ptr; pm <= pe; pm++) + switch (*pm) { + case LBRACKET: + /* Ignore everything between [] */ + for (pm1 = pm++; *pm != RBRACKET && *pm != EOS; pm++) + continue; + if (*pm == EOS) { + /* + * We could not find a matching RBRACKET. + * Ignore and just look for RBRACE + */ + pm = pm1; + } + break; + + case LBRACE: + i++; + break; + + case RBRACE: + if (i) { + i--; + break; + } + /* FALLTHROUGH */ + case COMMA: + if (i && *pm == COMMA) + break; + else { + /* Append the current string */ + for (lm = ls; (pl < pm); *lm++ = *pl++) + continue; + /* + * Append the rest of the pattern after the + * closing brace + */ + for (pl = pe + 1; (*lm++ = *pl++) != EOS;) + continue; + + /* Expand the current pattern */ +#ifdef DEBUG + qprintf("globexp2:", patbuf); +#endif + rv = globexp1(patbuf, pglob, limit); + if (rv) + return (rv); + + /* move after the comma, to the next string */ + pl = pm + 1; + } + break; + + default: + break; + } + return (0); +} + + + +/* + * expand tilde from the passwd file. + */ +static const Char * +globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) +{ + struct passwd *pwd; + char *h, *sc; + const Char *p; + Char *b, *eb; + wchar_t wc; + wchar_t wbuf[MAXPATHLEN]; + wchar_t *wbufend, *dc; + size_t clen; + mbstate_t mbs; + int too_long; + + if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE)) + return (pattern); + + /* + * Copy up to the end of the string or / + */ + eb = &patbuf[patbuf_len - 1]; + for (p = pattern + 1, b = patbuf; + b < eb && *p != EOS && UNPROT(*p) != SEP; *b++ = *p++) + continue; + + if (*p != EOS && UNPROT(*p) != SEP) + return (NULL); + + *b = EOS; + h = NULL; + + if (patbuf[0] == EOS) { + /* + * handle a plain ~ or ~/ by expanding $HOME first (iff + * we're not running setuid or setgid) and then trying + * the password file + */ + if ((h = secure_getenv("HOME")) == NULL) { + if (((h = getlogin()) != NULL && + (pwd = getpwnam(h)) != NULL) || + (pwd = getpwuid(getuid())) != NULL) + h = pwd->pw_dir; + else + return (pattern); + } + } + else { + /* + * Expand a ~user + */ + if (g_Ctoc(patbuf, (char *)wbuf, sizeof(wbuf))) + return (NULL); + if ((pwd = getpwnam((char *)wbuf)) == NULL) + return (pattern); + else + h = pwd->pw_dir; + } + + /* Copy the home directory */ + dc = wbuf; + sc = h; + wbufend = wbuf + MAXPATHLEN - 1; + too_long = 1; + memset(&mbs, 0, sizeof(mbs)); + while (dc <= wbufend) { + clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) { + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if ((*dc++ = wc) == EOS) { + too_long = 0; + break; + } + sc += clen; + } + if (too_long) + return (NULL); + + dc = wbuf; + for (b = patbuf; b < eb && *dc != EOS; *b++ = *dc++ | M_PROTECT) + continue; + if (*dc != EOS) + return (NULL); + + /* Append the rest of the pattern */ + if (*p != EOS) { + too_long = 1; + while (b <= eb) { + if ((*b++ = *p++) == EOS) { + too_long = 0; + break; + } + } + if (too_long) + return (NULL); + } else + *b = EOS; + + return (patbuf); +} + + +/* + * The main glob() routine: compiles the pattern (optionally processing + * quotes), calls glob1() to do the real pattern matching, and finally + * sorts the list (unless unsorted operation is requested). Returns 0 + * if things went well, nonzero if errors occurred. + */ +static int +glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit, + const char *origpat) { + const Char *qpatnext; + int err; + size_t oldpathc; + Char *bufnext, c, patbuf[MAXPATHLEN]; + + qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); + if (qpatnext == NULL) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + oldpathc = pglob->gl_pathc; + bufnext = patbuf; + + /* We don't need to check for buffer overflow any more. */ + while ((c = *qpatnext++) != EOS) { + switch (c) { + case LBRACKET: + c = *qpatnext; + if (c == NOT) + ++qpatnext; + if (*qpatnext == EOS || + g_strchr(qpatnext+1, RBRACKET) == NULL) { + *bufnext++ = LBRACKET; + if (c == NOT) + --qpatnext; + break; + } + *bufnext++ = M_SET; + if (c == NOT) + *bufnext++ = M_NOT; + c = *qpatnext++; + do { + *bufnext++ = CHAR(c); + if (*qpatnext == RANGE && + (c = qpatnext[1]) != RBRACKET) { + *bufnext++ = M_RNG; + *bufnext++ = CHAR(c); + qpatnext += 2; + } + } while ((c = *qpatnext++) != RBRACKET); + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_END; + break; + case QUESTION: + pglob->gl_flags |= GLOB_MAGCHAR; + *bufnext++ = M_ONE; + break; + case STAR: + pglob->gl_flags |= GLOB_MAGCHAR; + /* collapse adjacent stars to one, + * to ensure "**" at the end continues to match the + * empty string + */ + if (bufnext == patbuf || bufnext[-1] != M_ALL) + *bufnext++ = M_ALL; + break; + default: + *bufnext++ = CHAR(c); + break; + } + } + *bufnext = EOS; +#ifdef DEBUG + qprintf("glob0:", patbuf); +#endif + + if ((err = glob1(patbuf, pglob, limit)) != 0) + return(err); + + if (origpat != NULL) + return (globfinal(pglob, limit, oldpathc, origpat)); + + return (0); +} + +static int +globfinal(glob_t *pglob, struct glob_limit *limit, size_t oldpathc, + const char *origpat) { + if (pglob->gl_pathc == oldpathc) + return (err_nomatch(pglob, limit, origpat)); + + if (!(pglob->gl_flags & GLOB_NOSORT)) + qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, + pglob->gl_pathc - oldpathc, sizeof(char *), compare); + + return (0); +} + +static int +compare(const void *p, const void *q) +{ + return (strcoll(*(char **)p, *(char **)q)); +} + +static int +glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit) +{ + Char pathbuf[MAXPATHLEN]; + + /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */ + if (*pattern == EOS) + return (0); + return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1, + pattern, pglob, limit)); +} + +/* + * The functions glob2 and glob3 are mutually recursive; there is one level + * of recursion for each segment in the pattern that contains one or more + * meta characters. + */ +static int +glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, + glob_t *pglob, struct glob_limit *limit) +{ + struct stat sb; + Char *p, *q; + int anymeta; + + /* + * Loop over pattern segments until end of pattern or until + * segment with meta character found. + */ + for (anymeta = 0;;) { + if (*pattern == EOS) { /* End of pattern? */ + *pathend = EOS; + if (g_lstat(pathbuf, &sb, pglob)) + return (0); + + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + if ((pglob->gl_flags & GLOB_MARK) && + UNPROT(pathend[-1]) != SEP && + (S_ISDIR(sb.st_mode) || + (S_ISLNK(sb.st_mode) && + g_stat(pathbuf, &sb, pglob) == 0 && + S_ISDIR(sb.st_mode)))) { + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend++ = SEP; + *pathend = EOS; + } + ++pglob->gl_matchc; + return (globextend(pathbuf, pglob, limit, NULL)); + } + + /* Find end of next segment, copy tentatively to pathend. */ + q = pathend; + p = pattern; + while (*p != EOS && UNPROT(*p) != SEP) { + if (ismeta(*p)) + anymeta = 1; + if (q + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *q++ = *p++; + } + + if (!anymeta) { /* No expansion, do next segment. */ + pathend = q; + pattern = p; + while (UNPROT(*pattern) == SEP) { + if (pathend + 1 > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend++ = *pattern++; + } + } else /* Need expansion, recurse. */ + return (glob3(pathbuf, pathend, pathend_last, pattern, + p, pglob, limit)); + } + /* NOTREACHED */ +} + +static int +glob3(Char *pathbuf, Char *pathend, Char *pathend_last, + Char *pattern, Char *restpattern, + glob_t *pglob, struct glob_limit *limit) +{ + struct dirent *dp; + DIR *dirp; + int err, too_long, saverrno, saverrno2; + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + struct dirent *(*readdirfunc)(DIR *); + + if (pathend > pathend_last) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + *pathend = EOS; + if ((pglob->gl_errfunc != NULL || pglob->gl_errblk != NULL) && + g_Ctoc(pathbuf, buf, sizeof(buf))) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + + saverrno = errno; + errno = 0; + if ((dirp = g_opendir(pathbuf, pglob)) == NULL) { + if (errno == ENOENT || errno == ENOTDIR) + return (0); + err = err_aborted(pglob, errno, buf); + if (errno == 0) + errno = saverrno; + return (err); + } + + err = 0; + + /* pglob->gl_readdir takes a void *, fix this manually */ + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + readdirfunc = (struct dirent *(*)(DIR *))pglob->gl_readdir; + else + readdirfunc = readdir; + + errno = 0; + /* Search directory for matching names. */ + while ((dp = (*readdirfunc)(dirp)) != NULL) { + char *sc; + Char *dc; + wchar_t wc; + size_t clen; + mbstate_t mbs; + + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) { + errno = E2BIG; + err = GLOB_NOSPACE; + break; + } + + /* Initial DOT must be matched literally. */ + if (dp->d_name[0] == '.' && UNPROT(*pattern) != DOT) { + errno = 0; + continue; + } + memset(&mbs, 0, sizeof(mbs)); + dc = pathend; + sc = dp->d_name; + too_long = 1; + while (dc <= pathend_last) { + clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); + if (clen == (size_t)-1 || clen == (size_t)-2) { + /* XXX See initial comment #2. */ + wc = (unsigned char)*sc; + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if ((*dc++ = wc) == EOS) { + too_long = 0; + break; + } + sc += clen; + } + if (too_long && (err = err_aborted(pglob, ENAMETOOLONG, + buf))) { + errno = ENAMETOOLONG; + break; + } + if (too_long || !match(pathend, pattern, restpattern)) { + *pathend = EOS; + errno = 0; + continue; + } + if (errno == 0) + errno = saverrno; + err = glob2(pathbuf, --dc, pathend_last, restpattern, + pglob, limit); + if (err) + break; + errno = 0; + } + + saverrno2 = errno; + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + (*pglob->gl_closedir)(dirp); + else + closedir(dirp); + errno = saverrno2; + + if (err) + return (err); + + if (dp == NULL && errno != 0 && + (err = err_aborted(pglob, errno, buf))) + return (err); + + if (errno == 0) + errno = saverrno; + return (0); +} + + +/* + * Extend the gl_pathv member of a glob_t structure to accommodate a new item, + * add the new item, and update gl_pathc. + * + * This assumes the BSD realloc, which only copies the block when its size + * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic + * behavior. + * + * Return 0 if new item added, error code if memory couldn't be allocated. + * + * Invariant of the glob_t structure: + * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and + * gl_pathv points to (gl_offs + gl_pathc + 1) items. + */ +static int +globextend(const Char *path, glob_t *pglob, struct glob_limit *limit, + const char *origpat) +{ + char **pathv; + size_t i, newn, len; + char *copy; + const Char *p; + + if ((pglob->gl_flags & GLOB_LIMIT) && + pglob->gl_matchc > limit->l_path_lim) { + errno = E2BIG; + return (GLOB_NOSPACE); + } + + newn = 2 + pglob->gl_pathc + pglob->gl_offs; + /* reallocarray(NULL, newn, size) is equivalent to malloc(newn*size). */ + pathv = reallocarray(pglob->gl_pathv, newn, sizeof(*pathv)); + if (pathv == NULL) + return (GLOB_NOSPACE); + + if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { + /* first time around -- clear initial gl_offs items */ + pathv += pglob->gl_offs; + for (i = pglob->gl_offs + 1; --i > 0; ) + *--pathv = NULL; + } + pglob->gl_pathv = pathv; + + if (origpat != NULL) + copy = strdup(origpat); + else { + for (p = path; *p++ != EOS;) + continue; + len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ + if ((copy = malloc(len)) != NULL) { + if (g_Ctoc(path, copy, len)) { + free(copy); + errno = E2BIG; + return (GLOB_NOSPACE); + } + } + } + if (copy != NULL) { + limit->l_string_cnt += strlen(copy) + 1; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_string_cnt >= GLOB_LIMIT_STRING) { + free(copy); + errno = E2BIG; + return (GLOB_NOSPACE); + } + pathv[pglob->gl_offs + pglob->gl_pathc++] = copy; + } + pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; + return (copy == NULL ? GLOB_NOSPACE : 0); +} + +/* + * pattern matching function for filenames. + */ +static int +match(Char *name, Char *pat, Char *patend) +{ + int ok, negate_range; + Char c, k, *nextp, *nextn; + struct xlocale_collate *table = + (struct xlocale_collate*)__get_locale()->components[XLC_COLLATE]; + + nextn = NULL; + nextp = NULL; + + while (1) { + while (pat < patend) { + c = *pat++; + switch (c & M_MASK) { + case M_ALL: + if (pat == patend) + return (1); + if (*name == EOS) + return (0); + nextn = name + 1; + nextp = pat - 1; + break; + case M_ONE: + if (*name++ == EOS) + goto fail; + break; + case M_SET: + ok = 0; + if ((k = *name++) == EOS) + goto fail; + negate_range = ((*pat & M_MASK) == M_NOT); + if (negate_range != 0) + ++pat; + while (((c = *pat++) & M_MASK) != M_END) + if ((*pat & M_MASK) == M_RNG) { + if (table->__collate_load_error ? + CHAR(c) <= CHAR(k) && + CHAR(k) <= CHAR(pat[1]) : + __wcollate_range_cmp(CHAR(c), + CHAR(k)) <= 0 && + __wcollate_range_cmp(CHAR(k), + CHAR(pat[1])) <= 0) + ok = 1; + pat += 2; + } else if (c == k) + ok = 1; + if (ok == negate_range) + goto fail; + break; + default: + if (*name++ != c) + goto fail; + break; + } + } + if (*name == EOS) + return (1); + + fail: + if (nextn == NULL) + break; + pat = nextp; + name = nextn; + } + return (0); +} + +/* Free allocated data belonging to a glob_t structure. */ +void +globfree(glob_t *pglob) +{ + size_t i; + char **pp; + + if (pglob->gl_pathv != NULL) { + pp = pglob->gl_pathv + pglob->gl_offs; + for (i = pglob->gl_pathc; i--; ++pp) + if (*pp) + free(*pp); + free(pglob->gl_pathv); + pglob->gl_pathv = NULL; + } +} + +static DIR * +g_opendir(Char *str, glob_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (*str == EOS) + strcpy(buf, "."); + else { + if (g_Ctoc(str, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (NULL); + } + } + + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return ((*pglob->gl_opendir)(buf)); + + return (opendir(buf)); +} + +static int +g_lstat(Char *fn, struct stat *sb, glob_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (g_Ctoc(fn, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (-1); + } + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return((*pglob->gl_lstat)(buf, sb)); + return (lstat(buf, sb)); +} + +static int +g_stat(Char *fn, struct stat *sb, glob_t *pglob) +{ + char buf[MAXPATHLEN + MB_LEN_MAX - 1]; + + if (g_Ctoc(fn, buf, sizeof(buf))) { + errno = ENAMETOOLONG; + return (-1); + } + if (pglob->gl_flags & GLOB_ALTDIRFUNC) + return ((*pglob->gl_stat)(buf, sb)); + return (stat(buf, sb)); +} + +static const Char * +g_strchr(const Char *str, wchar_t ch) +{ + + do { + if (*str == ch) + return (str); + } while (*str++); + return (NULL); +} + +static int +g_Ctoc(const Char *str, char *buf, size_t len) +{ + mbstate_t mbs; + size_t clen; + + memset(&mbs, 0, sizeof(mbs)); + while (len >= MB_CUR_MAX) { + clen = wcrtomb(buf, CHAR(*str), &mbs); + if (clen == (size_t)-1) { + /* XXX See initial comment #2. */ + *buf = (char)CHAR(*str); + clen = 1; + memset(&mbs, 0, sizeof(mbs)); + } + if (CHAR(*str) == EOS) + return (0); + str++; + buf += clen; + len -= clen; + } + return (1); +} + +static int +err_nomatch(glob_t *pglob, struct glob_limit *limit, const char *origpat) { + /* + * If there was no match we are going to append the origpat + * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified + * and the origpat did not contain any magic characters + * GLOB_NOMAGIC is there just for compatibility with csh. + */ + if ((pglob->gl_flags & GLOB_NOCHECK) || + ((pglob->gl_flags & GLOB_NOMAGIC) && + !(pglob->gl_flags & GLOB_MAGCHAR))) + return (globextend(NULL, pglob, limit, origpat)); + return (GLOB_NOMATCH); +} + +static int +err_aborted(glob_t *pglob, int err, char *buf) +{ + int rv = 0; + + if ((pglob->gl_flags & _GLOB_ERR_BLOCK) != 0) { + if (pglob->gl_errblk != NULL) + rv = CALL_BLOCK((glob_b_block)pglob->gl_errblk, buf, + errno); + } else if (pglob->gl_errfunc != NULL) { + rv = pglob->gl_errfunc(buf, errno); + } + /* GLOB_ERR is allowed to override the error callback function. */ + if (rv != 0 || pglob->gl_flags & GLOB_ERR) { + return (GLOB_ABORTED); + } + return (0); +} + +#ifdef DEBUG +static void +qprintf(const char *str, Char *s) +{ + Char *p; + + (void)printf("%s\n", str); + if (s != NULL) { + for (p = s; *p != EOS; p++) + (void)printf("%c", (char)CHAR(*p)); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (isprot(*p) ? '\\' : ' ')); + (void)printf("\n"); + for (p = s; *p != EOS; p++) + (void)printf("%c", (ismeta(*p) ? '_' : ' ')); + (void)printf("\n"); + } +} +#endif diff --git a/lib/libc/gen/initgroups.3 b/lib/libc/gen/initgroups.3 new file mode 100644 index 000000000000..4f538fb180ec --- /dev/null +++ b/lib/libc/gen/initgroups.3 @@ -0,0 +1,150 @@ +.\"- +.\" SPDX-License-Identifier: BSD-3-Clause +.\" +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" Copyright (c) 2025 The FreeBSD Foundation +.\" +.\" Portions of this documentation were written by Olivier Certner +.\" <olce@FreeBSD.org> at Kumacom SARL under sponsorship from the FreeBSD +.\" Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd September 17, 2025 +.Dt INITGROUPS 3 +.Os +.Sh NAME +.Nm initgroups +.Nd initialize supplementary groups as per the group database +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn initgroups "const char *name" "gid_t basegid" +.Sh DESCRIPTION +The +.Fn initgroups +function initializes the current process' supplementary groups as prescribed by +its arguments and the system's group database. +.Pp +It first uses the +.Fn getgrouplist +function to compute a list of groups containing the passed +.Fa basegid , +which typically is the user's initial numerical group ID from the password +database, and the supplementary groups in the group database for the user named +.Fa name . +It then installs this list as the current process' supplementary groups using +.Fn setgroups . +.Sh RETURN VALUES +.Rv -std initgroups +.Sh ERRORS +The +.Fn initgroups +function may fail and set +.Va errno +to any of the errors specified for the library function +.Xr setgroups 2 . +It may also return: +.Bl -tag -width Er +.It Bq Er ENOMEM +The +.Fn initgroups +function was unable to allocate temporary storage. +.El +.Sh SEE ALSO +.Xr setgroups 2 , +.Xr getgrouplist 3 +.Sh HISTORY +The +.Fn initgroups +function appeared in +.Bx 4.2 . +.Pp +The +.Fn initgroups +function changed semantics in +.Fx 15 , +following that of +.Xr setgroups 2 +in the same release. +Before that, it would also set the effective group ID to +.Fa basegid , +and would not include the latter in the supplementary groups except before +.Fx 8 . +Its current behavior in these respects is known to be compatible with that of +the following systems up to the specified versions that are current at time of +this writing: +.Bl -dash -width "-" -compact +.It +Linux (up to 6.6) with the GNU libc (up to 2.42) +.It +.Nx 1.1 and greater (up to 10) +.It +.Ox (up to 7.7) +.It +Systems based on illumos (up to August 2025 sources) +.El +.Sh SECURITY CONSIDERATIONS +As +.Fa basegid +is typically the user's initial numerical group ID, to which the current +process' effective group ID is generally initialized, processes using functions +to change their effective group ID +.Pq via Xr setgid 2 or similar +or that are spawned from executables with the set-group-ID mode bit set will not +be able to relinquish the access rights deriving from being a member of +.Fa basegid , +as these functions do not change the supplementary groups. +.Pp +This behavior is generally desirable in order to paper over the difference of +treatment between the effective group and supplementary ones in this situation, +as they are all in the end indiscriminately used in traditional UNIX +discretionary access checks. +It blends well with the practice of allocating each user its own private group, +as processes launched from a set-group-ID executable keep the same user and +consistently stay also in the same user's group. +Finally, it was also chosen for compatibility with other systems +.Po +see the +.Sx HISTORY +section +.Pc . +.Pp +This convention of including +.Fa basegid +in the supplementary groups is however only enforced by the +.Fn initgroups +function, and not by the +.Xr setgroups 2 +system call, so applications expressly wanting to include in the supplementary +groups only those specified by the group database can themselves call +.Fn getgrouplist +and then +.Fn setgroups +on the result with the first element skipped +.Pq see Xr getgrouplist 3 . diff --git a/lib/libc/gen/initgroups.c b/lib/libc/gen/initgroups.c new file mode 100644 index 000000000000..a1a7d92250e2 --- /dev/null +++ b/lib/libc/gen/initgroups.c @@ -0,0 +1,85 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * Copyright (c) 2025 The FreeBSD Foundation + * + * Portions of this software were developed by Olivier Certner + * <olce@FreeBSD.org> at Kumacom SARL under sponsorship from the FreeBSD + * Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* For __sym_compat(). */ +#include <sys/cdefs.h> + +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> + +/* For freebsd14_setgroups(). */ +#include "gen-compat.h" + +static int +initgroups_impl(const char *uname, gid_t agroup, + int (*setgroups)(int, const gid_t *)) +{ + gid_t *groups; + long ngroups_max; + int ngroups, ret; + + /* + * Provide space for one group more than possible to allow setgroups() + * to fail and set 'errno' in case we get back more than {NGROUPS_MAX} + + * 1 groups. + */ + ngroups_max = sysconf(_SC_NGROUPS_MAX) + 2; + groups = malloc(sizeof(*groups) * ngroups_max); + if (groups == NULL) + return (-1); /* malloc() set 'errno'. */ + + ngroups = (int)ngroups_max; + (void)getgrouplist(uname, agroup, groups, &ngroups); + ret = (*setgroups)(ngroups, groups); + + free(groups); + return (ret); /* setgroups() set 'errno'. */ +} + +int +initgroups(const char *uname, gid_t agroup) +{ + return (initgroups_impl(uname, agroup, setgroups)); +} + +int +freebsd14_initgroups(const char *uname, gid_t agroup) +{ + return (initgroups_impl(uname, agroup, freebsd14_setgroups)); +} + +__sym_compat(initgroups, freebsd14_initgroups, FBSD_1.0); diff --git a/lib/libc/gen/inotify.c b/lib/libc/gen/inotify.c new file mode 100644 index 000000000000..7ce53aaccd58 --- /dev/null +++ b/lib/libc/gen/inotify.c @@ -0,0 +1,48 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Klara, Inc. + */ + +#include "namespace.h" +#include <sys/fcntl.h> +#include <sys/inotify.h> +#include <sys/specialfd.h> +#include "un-namespace.h" +#include "libc_private.h" + +/* + * Provide compatibility with libinotify, which uses different values for these + * flags. + */ +#define IN_NONBLOCK_OLD 0x80000 +#define IN_CLOEXEC_OLD 0x00800 + +int +inotify_add_watch(int fd, const char *pathname, uint32_t mask) +{ + return (inotify_add_watch_at(fd, AT_FDCWD, pathname, mask)); +} + +int +inotify_init1(int flags) +{ + struct specialfd_inotify args; + + if ((flags & IN_NONBLOCK_OLD) != 0) { + flags &= ~IN_NONBLOCK_OLD; + flags |= IN_NONBLOCK; + } + if ((flags & IN_CLOEXEC_OLD) != 0) { + flags &= ~IN_CLOEXEC_OLD; + flags |= IN_CLOEXEC; + } + args.flags = flags; + return (__sys___specialfd(SPECIALFD_INOTIFY, &args, sizeof(args))); +} + +int +inotify_init(void) +{ + return (inotify_init1(0)); +} diff --git a/lib/libc/gen/isatty.c b/lib/libc/gen/isatty.c new file mode 100644 index 000000000000..8844f3121538 --- /dev/null +++ b/lib/libc/gen/isatty.c @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <termios.h> +#include <unistd.h> + +int +isatty(int fd) +{ + int retval; + struct termios t; + + retval = (tcgetattr(fd, &t) != -1); + return(retval); +} diff --git a/lib/libc/gen/isgreater.3 b/lib/libc/gen/isgreater.3 new file mode 100644 index 000000000000..279867a2ba36 --- /dev/null +++ b/lib/libc/gen/isgreater.3 @@ -0,0 +1,100 @@ +.\" Copyright (c) 2003 David Schultz <das@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd February 12, 2003 +.Dt ISGREATER 3 +.Os +.Sh NAME +.Nm isgreater , isgreaterequal , isless , islessequal , +.Nm islessgreater , isunordered +.Nd "compare two floating-point numbers" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In math.h +.Ft int +.Fn isgreater "real-floating x" "real-floating y" +.Ft int +.Fn isgreaterequal "real-floating x" "real-floating y" +.Ft int +.Fn isless "real-floating x" "real-floating y" +.Ft int +.Fn islessequal "real-floating x" "real-floating y" +.Ft int +.Fn islessgreater "real-floating x" "real-floating y" +.Ft int +.Fn isunordered "real-floating x" "real-floating y" +.Sh DESCRIPTION +Each of the macros +.Fn isgreater , +.Fn isgreaterequal , +.Fn isless , +.Fn islessequal , +and +.Fn islessgreater +take arguments +.Fa x +and +.Fa y +and return a non-zero value if and only if its nominal +relation on +.Fa x +and +.Fa y +is true. +These macros always return zero if either +argument is not a number (NaN), but unlike the corresponding C +operators, they never raise a floating point exception. +.Pp +The +.Fn isunordered +macro takes arguments +.Fa x +and +.Fa y +and returns non-zero if and only if any of +.Fa x +or +.Fa y +are NaNs. +For any pair of floating-point values, one +of the relationships (less, greater, equal, unordered) holds. +.Sh SEE ALSO +.Xr fpclassify 3 , +.Xr math 3 , +.Xr signbit 3 +.Sh STANDARDS +The +.Fn isgreater , +.Fn isgreaterequal , +.Fn isless , +.Fn islessequal , +.Fn islessgreater , +and +.Fn isunordered +macros conform to +.St -isoC-99 . +.Sh HISTORY +The relational macros described above first appeared in +.Fx 5.1 . diff --git a/lib/libc/gen/isinf.c b/lib/libc/gen/isinf.c new file mode 100644 index 000000000000..3f4fdacb791f --- /dev/null +++ b/lib/libc/gen/isinf.c @@ -0,0 +1,72 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <machine/float.h> + +#include <math.h> + +#include "fpmath.h" + +/* + * XXX These routines belong in libm, but they must remain in libc for + * binary compat until we can bump libm's major version number. + */ + +__weak_reference(__isinf, isinf); + +int +__isinf(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0); +} + +int +__isinff(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp == 255 && u.bits.man == 0); +} + +int +__isinfl(long double e) +{ + union IEEEl2bits u; + + u.e = e; + mask_nbit_l(u); +#if LDBL_MANT_DIG == 53 + return (u.bits.exp == 2047 && u.bits.manl == 0 && u.bits.manh == 0); +#else + return (u.bits.exp == 32767 && u.bits.manl == 0 && u.bits.manh == 0); +#endif +} diff --git a/lib/libc/gen/isnan.c b/lib/libc/gen/isnan.c new file mode 100644 index 000000000000..e6e2b16a92ce --- /dev/null +++ b/lib/libc/gen/isnan.c @@ -0,0 +1,71 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004 David Schultz <das@FreeBSD.ORG> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <math.h> + +#include "fpmath.h" + +/* + * XXX These routines belong in libm, but they must remain in libc for + * binary compat until we can bump libm's major version number. + * + * Note this only applies to the dynamic versions of libm and libc, so + * for the static and profiled versions we stub out the definitions. + * Otherwise you cannot link statically to libm and libc at the same + * time, when calling both functions. + */ + +#ifdef PIC +/* + * Because math.h defines __isnan and __isnanf as aliases for compatibility with + * glibc and CUDA, we have to undefine them here to avoid redefinition errors. + */ +#undef __isnan +#undef __isnanf + +__weak_reference(__isnan, isnan); +__weak_reference(__isnanf, isnanf); + +int +__isnan(double d) +{ + union IEEEd2bits u; + + u.d = d; + return (u.bits.exp == 2047 && (u.bits.manl != 0 || u.bits.manh != 0)); +} + +int +__isnanf(float f) +{ + union IEEEf2bits u; + + u.f = f; + return (u.bits.exp == 255 && u.bits.man != 0); +} +#endif /* PIC */ diff --git a/lib/libc/gen/jrand48.c b/lib/libc/gen/jrand48.c new file mode 100644 index 000000000000..93442439d49e --- /dev/null +++ b/lib/libc/gen/jrand48.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +long +jrand48(unsigned short xseed[3]) +{ + uint48 tmp; + + DORAND48(tmp, xseed); + return ((int)((tmp >> 16) & 0xffffffff)); +} diff --git a/lib/libc/gen/kqueue1.c b/lib/libc/gen/kqueue1.c new file mode 100644 index 000000000000..b27a8f63019e --- /dev/null +++ b/lib/libc/gen/kqueue1.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2023 The FreeBSD Foundation + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/event.h> +#include <errno.h> +#include <fcntl.h> + +/* + * Provide some NetBSD compatibility. They support a set of O_* + * flags, we only carry O_CLOEXEC, and accept but ignore O_NONBLOCK. + */ +int +kqueue1(int openflags) +{ + u_int flags; + + if ((openflags & ~(O_CLOEXEC | O_NONBLOCK)) != 0) { + errno = EINVAL; + return (-1); + } + + flags = 0; + if ((openflags & O_CLOEXEC) != 0) + flags |= KQUEUE_CLOEXEC; + return (kqueuex(flags)); +} diff --git a/lib/libc/gen/lcong48.c b/lib/libc/gen/lcong48.c new file mode 100644 index 000000000000..871b2110ed94 --- /dev/null +++ b/lib/libc/gen/lcong48.c @@ -0,0 +1,22 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +void +lcong48(unsigned short p[7]) +{ + LOADRAND48(_rand48_seed, &p[0]); + LOADRAND48(_rand48_mult, &p[3]); + _rand48_add = p[6]; +} diff --git a/lib/libc/gen/ldexp.3 b/lib/libc/gen/ldexp.3 new file mode 100644 index 000000000000..d89dea2d16c7 --- /dev/null +++ b/lib/libc/gen/ldexp.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd March 4, 2005 +.Dt LDEXP 3 +.Os +.Sh NAME +.Nm ldexp , +.Nm ldexpf , +.Nm ldexpl +.Nd multiply floating-point number by integral power of 2 +.Sh LIBRARY +.Lb libm +.Sh SYNOPSIS +.In math.h +.Ft double +.Fn ldexp "double x" "int exp" +.Ft float +.Fn ldexpf "float x" "int exp" +.Ft long double +.Fn ldexpl "long double x" "int exp" +.Sh DESCRIPTION +The +.Fn ldexp , +.Fn ldexpf , +and +.Fn ldexpl +functions multiply a floating-point number by an integral +power of 2. +.Sh RETURN VALUES +These functions return the value of +.Fa x +times 2 raised to the power +.Fa exp . +.Sh SEE ALSO +.Xr frexp 3 , +.Xr math 3 , +.Xr modf 3 +.Sh STANDARDS +The +.Fn ldexp , +.Fn ldexpf , +and +.Fn ldexpl +functions conform to +.St -isoC-99 . diff --git a/lib/libc/gen/ldexp.c b/lib/libc/gen/ldexp.c new file mode 100644 index 000000000000..1db62afc609e --- /dev/null +++ b/lib/libc/gen/ldexp.c @@ -0,0 +1,7 @@ +/* + * ldexp() and scalbn() are defined to be identical, but ldexp() lives in libc + * for backwards compatibility. + */ +#define scalbn ldexp +#include "../../msun/src/s_scalbn.c" +#undef scalbn diff --git a/lib/libc/gen/libc_dlopen.c b/lib/libc/gen/libc_dlopen.c new file mode 100644 index 000000000000..4e5ec2961ac2 --- /dev/null +++ b/lib/libc/gen/libc_dlopen.c @@ -0,0 +1,56 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2011 Xin LI <delphij@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <dlfcn.h> +#include <stddef.h> +#include <unistd.h> + +#include "libc_private.h" + +/* + * Whether we want to restrict dlopen()s. + */ +static int __libc_restricted_mode = 0; + +void * +libc_dlopen(const char *path, int mode) +{ + + if (__libc_restricted_mode) { + _rtld_error("Service unavailable -- libc in restricted mode"); + return (NULL); + } + return (dlopen(path, mode)); +} + +void +__FreeBSD_libc_enter_restricted_mode(void) +{ + + __libc_restricted_mode = 1; +} + diff --git a/lib/libc/gen/libc_interposing_table.c b/lib/libc/gen/libc_interposing_table.c new file mode 100644 index 000000000000..025a67ac3eac --- /dev/null +++ b/lib/libc/gen/libc_interposing_table.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2014 The FreeBSD Foundation. + * + * Portions of this software were developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <stddef.h> +#include "libc_private.h" + +#define SLOT(a, b) \ + [INTERPOS_##a] = (interpos_func_t)b +interpos_func_t __libc_interposing[INTERPOS_MAX] = { + SLOT(system, __libc_system), + SLOT(tcdrain, __libc_tcdrain), + SLOT(_pthread_mutex_init_calloc_cb, _pthread_mutex_init_calloc_cb_stub), + SLOT(spinlock, __libc_spinlock_stub), + SLOT(spinunlock, __libc_spinunlock_stub), + SLOT(map_stacks_exec, __libc_map_stacks_exec), + SLOT(uexterr_gettext, __libc_uexterr_gettext), +}; +#undef SLOT + +interpos_func_t * +__libc_interposing_slot(int interposno) +{ + if (__libc_interposing[interposno] == NULL) + return (__libsys_interposing_slot(interposno)); + return (&__libc_interposing[interposno]); +} diff --git a/lib/libc/gen/lrand48.c b/lib/libc/gen/lrand48.c new file mode 100644 index 000000000000..cc07044b8af9 --- /dev/null +++ b/lib/libc/gen/lrand48.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +long +lrand48(void) +{ + _DORAND48(_rand48_seed); + return (_rand48_seed >> 17) & 0x7fffffff; +} diff --git a/lib/libc/gen/makecontext.3 b/lib/libc/gen/makecontext.3 new file mode 100644 index 000000000000..198c541d40a6 --- /dev/null +++ b/lib/libc/gen/makecontext.3 @@ -0,0 +1,162 @@ +.\" Copyright (c) 2002 Packet Design, LLC. +.\" All rights reserved. +.\" +.\" Subject to the following obligations and disclaimer of warranty, +.\" use and redistribution of this software, in source or object code +.\" forms, with or without modifications are expressly permitted by +.\" Packet Design; provided, however, that: +.\" +.\" (i) Any and all reproductions of the source or object code +.\" must include the copyright notice above and the following +.\" disclaimer of warranties; and +.\" (ii) No rights are granted, in any manner or form, to use +.\" Packet Design trademarks, including the mark "PACKET DESIGN" +.\" on advertising, endorsements, or otherwise except as such +.\" appears in the above copyright notice or in the software. +.\" +.\" THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND +.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO +.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING +.\" THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +.\" OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, +.\" OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS +.\" OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, +.\" RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE +.\" LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE +.\" OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL +.\" DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF +.\" USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +.\" THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF +.\" THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd March 23, 2020 +.Dt MAKECONTEXT 3 +.Os +.Sh NAME +.Nm makecontext , swapcontext +.Nd modify and exchange user thread contexts +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In ucontext.h +.Ft void +.Fo makecontext +.Fa "ucontext_t *ucp" +.Fa "void \*[lp]*func\*[rp]\*[lp]void\*[rp]" +.Fa "int argc" ... +.Fc +.Ft int +.Fn swapcontext "ucontext_t *oucp" "const ucontext_t *ucp" +.Sh DESCRIPTION +The +.Fn makecontext +function +modifies the user thread context pointed to by +.Fa ucp , +which must have previously been initialized by a call to +.Xr getcontext 3 +and had a stack allocated for it. +The context is modified so that it will continue execution by invoking +.Fn func +with the arguments provided. +The +.Fa argc +argument +must be equal to the number of additional arguments of type +.Vt int +provided to +.Fn makecontext +and also equal to the number of arguments of type +.Vt int +to +.Fn func ; +otherwise , +the behavior is undefined. +.Pp +The +.Fa "ucp->uc_link" +argument +must be initialized before calling +.Fn makecontext +and determines the action to take when +.Fn func +returns: +if equal to +.Dv NULL , +the process exits; +otherwise, +.Fn setcontext "ucp->uc_link" +is implicitly invoked. +.Pp +The +.Fn swapcontext +function +saves the current thread context in +.Fa "*oucp" +and makes +.Fa "*ucp" +the currently active context. +.Sh RETURN VALUES +If successful, +.Fn swapcontext +returns zero; +otherwise \-1 is returned and the global variable +.Va errno +is set appropriately. +.Sh ERRORS +The +.Fn swapcontext +function +will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +There is not enough stack space in +.Fa ucp +to complete the operation. +.El +.Sh SEE ALSO +.Xr setcontext 3 , +.Xr ucontext 3 +.Sh STANDARDS +The +.Fn makecontext +and +.Fn swapcontext +functions conform to +.St -xsh5 +and +.St -p1003.1-2001 . +.Pp +The +.St -p1003.1-2004 +revision marked the functions +.Fn makecontext +and +.Fn swapcontext +as obsolete, citing portability issues and recommending the use of +.Tn POSIX +threads instead. +The +.St -p1003.1-2008 +revision removed the functions from the specification. +.Pp +.Bf -symbolic +The standard does not clearly define the type of integer arguments +passed to +.Fa func +via +.Fn makecontext ; +portable applications should not rely on the implementation detail that +it may be possible to pass pointer arguments to functions. +.Ef +.Sh HISTORY +The +.Fn makecontext +and +.Fn swapcontext +functions first appeared in +.At V.4 . diff --git a/lib/libc/gen/memalign.c b/lib/libc/gen/memalign.c new file mode 100644 index 000000000000..269a5bc829b1 --- /dev/null +++ b/lib/libc/gen/memalign.c @@ -0,0 +1,43 @@ +/*- + * Copyright (c) 2020 The FreeBSD Foundation + * + * This software was developed by Konstantin Belousov + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <stdlib.h> + +void * +memalign(size_t align, size_t size) +{ + /* + * glibc allows align == 0, but that is not valid for roundup. + * Just pass through to malloc in that case. + */ + if (align != 0) + return (aligned_alloc(align, roundup(size, align))); + else + return (malloc(size)); +} diff --git a/lib/libc/gen/memfd_create.c b/lib/libc/gen/memfd_create.c new file mode 100644 index 000000000000..78131f46d7b1 --- /dev/null +++ b/lib/libc/gen/memfd_create.c @@ -0,0 +1,121 @@ +/* + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2019 Kyle Evans <kevans@FreeBSD.org> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/filio.h> +#include <sys/mman.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "libc_private.h" + +#define MEMFD_NAME_PREFIX "memfd:" + +/* + * The path argument is passed to the kernel, but the kernel doesn't currently + * do anything with it. Linux exposes it in linprocfs for debugging purposes + * only, but our kernel currently will not do the same. + */ +int +memfd_create(const char *name, unsigned int flags) +{ + char memfd_name[NAME_MAX + 1]; + size_t pgs[MAXPAGESIZES]; + size_t namelen, pgsize; + struct shm_largepage_conf slc; + int error, fd, npgs, oflags, pgidx, saved_errno, shmflags; + + if (name == NULL) { + errno = EBADF; + return (-1); + } + namelen = strlen(name); + if (namelen + sizeof(MEMFD_NAME_PREFIX) - 1 > NAME_MAX) { + errno = EINVAL; + return (-1); + } + if ((flags & ~(MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_HUGETLB | + MFD_HUGE_MASK)) != 0) { + errno = EINVAL; + return (-1); + } + /* Size specified but no HUGETLB. */ + if ((flags & MFD_HUGE_MASK) != 0 && (flags & MFD_HUGETLB) == 0) { + errno = EINVAL; + return (-1); + } + + /* We've already validated that we're sufficiently sized. */ + snprintf(memfd_name, NAME_MAX + 1, "%s%s", MEMFD_NAME_PREFIX, name); + oflags = O_RDWR; + shmflags = 0; + if ((flags & MFD_CLOEXEC) != 0) + oflags |= O_CLOEXEC; + if ((flags & MFD_ALLOW_SEALING) != 0) + shmflags |= SHM_ALLOW_SEALING; + if ((flags & MFD_HUGETLB) != 0) + shmflags |= SHM_LARGEPAGE; + else + shmflags |= SHM_GROW_ON_WRITE; + fd = __sys_shm_open2(SHM_ANON, oflags, 0, shmflags, memfd_name); + if (fd == -1 || (flags & MFD_HUGETLB) == 0) + return (fd); + + npgs = getpagesizes(pgs, nitems(pgs)); + if (npgs == -1) + goto clean; + pgsize = (size_t)1 << ((flags & MFD_HUGE_MASK) >> MFD_HUGE_SHIFT); + for (pgidx = 0; pgidx < npgs; pgidx++) { + if (pgsize == pgs[pgidx]) + break; + } + if (pgidx == npgs) { + errno = EOPNOTSUPP; + goto clean; + } + + memset(&slc, 0, sizeof(slc)); + slc.psind = pgidx; + slc.alloc_policy = SHM_LARGEPAGE_ALLOC_DEFAULT; + error = ioctl(fd, FIOSSHMLPGCNF, &slc); + if (error == -1) + goto clean; + return (fd); + +clean: + saved_errno = errno; + close(fd); + errno = saved_errno; + return (-1); +} diff --git a/lib/libc/gen/modf.3 b/lib/libc/gen/modf.3 new file mode 100644 index 000000000000..9d698ff62ce6 --- /dev/null +++ b/lib/libc/gen/modf.3 @@ -0,0 +1,78 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd March 29, 2008 +.Dt MODF 3 +.Os +.Sh NAME +.Nm modf , +.Nm modff , +.Nm modfl +.Nd extract signed integral and fractional values from floating-point number +.Sh LIBRARY +.Lb libm +.Sh SYNOPSIS +.In math.h +.Ft double +.Fn modf "double value" "double *iptr" +.Ft float +.Fn modff "float value" "float *iptr" +.Ft long double +.Fn modfl "long double value" "long double *iptr" +.Sh DESCRIPTION +The +.Fn modf , +.Fn modff , +and +.Fn modfl +functions break the argument +.Fa value +into integral and fractional parts, each of which has the +same sign as the argument. +It stores the integral part as a +floating point number +in the object pointed to by +.Fa iptr . +.Sh RETURN VALUES +These functions return the signed fractional part of +.Fa value . +.Sh SEE ALSO +.Xr frexp 3 , +.Xr ldexp 3 , +.Xr math 3 +.Sh STANDARDS +The +.Fn modf , +.Fn modff , +and +.Fn modfl +functions conform to +.St -isoC-99 . diff --git a/lib/libc/gen/modf.c b/lib/libc/gen/modf.c new file mode 100644 index 000000000000..b4093d6e930c --- /dev/null +++ b/lib/libc/gen/modf.c @@ -0,0 +1,134 @@ +/* + * ==================================================== + * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. + * + * Developed at SunPro, a Sun Microsystems, Inc. business. + * Permission to use, copy, modify, and distribute this + * software is freely granted, provided that this notice + * is preserved. + * ==================================================== + */ + +/* + * modf(double x, double *iptr) + * return fraction part of x, and return x's integral part in *iptr. + * Method: + * Bit twiddling. + * + * Exception: + * No exception. + */ + +#include <sys/types.h> +#include <machine/endian.h> +#include <math.h> + +/* Bit fiddling routines copied from msun/src/math_private.h,v 1.15 */ + +#if BYTE_ORDER == BIG_ENDIAN + +typedef union +{ + double value; + struct + { + u_int32_t msw; + u_int32_t lsw; + } parts; +} ieee_double_shape_type; + +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN + +typedef union +{ + double value; + struct + { + u_int32_t lsw; + u_int32_t msw; + } parts; +} ieee_double_shape_type; + +#endif + +/* Get two 32 bit ints from a double. */ + +#define EXTRACT_WORDS(ix0,ix1,d) \ +do { \ + ieee_double_shape_type ew_u; \ + ew_u.value = (d); \ + (ix0) = ew_u.parts.msw; \ + (ix1) = ew_u.parts.lsw; \ +} while (0) + +/* Get the more significant 32 bit int from a double. */ + +#define GET_HIGH_WORD(i,d) \ +do { \ + ieee_double_shape_type gh_u; \ + gh_u.value = (d); \ + (i) = gh_u.parts.msw; \ +} while (0) + +/* Set a double from two 32 bit ints. */ + +#define INSERT_WORDS(d,ix0,ix1) \ +do { \ + ieee_double_shape_type iw_u; \ + iw_u.parts.msw = (ix0); \ + iw_u.parts.lsw = (ix1); \ + (d) = iw_u.value; \ +} while (0) + +static const double one = 1.0; + +double +modf(double x, double *iptr) +{ + int32_t i0,i1,j0; + u_int32_t i; + EXTRACT_WORDS(i0,i1,x); + j0 = ((i0>>20)&0x7ff)-0x3ff; /* exponent of x */ + if(j0<20) { /* integer part in high x */ + if(j0<0) { /* |x|<1 */ + INSERT_WORDS(*iptr,i0&0x80000000,0); /* *iptr = +-0 */ + return x; + } else { + i = (0x000fffff)>>j0; + if(((i0&i)|i1)==0) { /* x is integral */ + u_int32_t high; + *iptr = x; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0&(~i),0); + return x - *iptr; + } + } + } else if (j0>51) { /* no fraction part */ + u_int32_t high; + if (j0 == 0x400) { /* inf/NaN */ + *iptr = x; + return 0.0 / x; + } + *iptr = x*one; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { /* fraction part in low x */ + i = ((u_int32_t)(0xffffffff))>>(j0-20); + if((i1&i)==0) { /* x is integral */ + u_int32_t high; + *iptr = x; + GET_HIGH_WORD(high,x); + INSERT_WORDS(x,high&0x80000000,0); /* return +-0 */ + return x; + } else { + INSERT_WORDS(*iptr,i0,i1&(~i)); + return x - *iptr; + } + } +} diff --git a/lib/libc/gen/mrand48.c b/lib/libc/gen/mrand48.c new file mode 100644 index 000000000000..f9128a6d4188 --- /dev/null +++ b/lib/libc/gen/mrand48.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include <stdint.h> + +#include "rand48.h" + +long +mrand48(void) +{ + _DORAND48(_rand48_seed); + return ((int)((_rand48_seed >> 16) & 0xffffffff)); +} diff --git a/lib/libc/gen/nftw-compat11.c b/lib/libc/gen/nftw-compat11.c new file mode 100644 index 000000000000..36970424bf2a --- /dev/null +++ b/lib/libc/gen/nftw-compat11.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + * + * From: $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $ + * From: FreeBSD: head/lib/libc/gen/nftw.c 239160 2012-08-09 22:05:40Z jilles + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fts.h> +#include <ftw.h> + +#include "fts-compat11.h" + +int +freebsd11_nftw(const char *path, + int (*fn)(const char *, const struct freebsd11_stat *, int, struct FTW *), + int nfds, int ftwflags) +{ + char * const paths[2] = { (char *)path, NULL }; + struct FTW ftw; + FTSENT11 *cur; + FTS11 *ftsp; + int error = 0, ftsflags, fnflag, postorder, sverrno; + + /* XXX - nfds is currently unused */ + if (nfds < 1) { + errno = EINVAL; + return (-1); + } + + ftsflags = FTS_COMFOLLOW; + if (!(ftwflags & FTW_CHDIR)) + ftsflags |= FTS_NOCHDIR; + if (ftwflags & FTW_MOUNT) + ftsflags |= FTS_XDEV; + if (ftwflags & FTW_PHYS) + ftsflags |= FTS_PHYSICAL; + else + ftsflags |= FTS_LOGICAL; + postorder = (ftwflags & FTW_DEPTH) != 0; + ftsp = freebsd11_fts_open(paths, ftsflags, NULL); + if (ftsp == NULL) + return (-1); + while ((cur = freebsd11_fts_read(ftsp)) != NULL) { + switch (cur->fts_info) { + case FTS_D: + if (postorder) + continue; + fnflag = FTW_D; + break; + case FTS_DC: + continue; + case FTS_DNR: + fnflag = FTW_DNR; + break; + case FTS_DP: + if (!postorder) + continue; + fnflag = FTW_DP; + break; + case FTS_F: + case FTS_DEFAULT: + fnflag = FTW_F; + break; + case FTS_NS: + case FTS_NSOK: + fnflag = FTW_NS; + break; + case FTS_SL: + fnflag = FTW_SL; + break; + case FTS_SLNONE: + fnflag = FTW_SLN; + break; + default: + error = -1; + goto done; + } + ftw.base = cur->fts_pathlen - cur->fts_namelen; + ftw.level = cur->fts_level; + error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw); + if (error != 0) + break; + } +done: + sverrno = errno; + if (freebsd11_fts_close(ftsp) != 0 && error == 0) + error = -1; + else + errno = sverrno; + return (error); +} + +__sym_compat(nftw, freebsd11_nftw, FBSD_1.0); diff --git a/lib/libc/gen/nftw.c b/lib/libc/gen/nftw.c new file mode 100644 index 000000000000..95cc9947b7c1 --- /dev/null +++ b/lib/libc/gen/nftw.c @@ -0,0 +1,106 @@ +/* $OpenBSD: nftw.c,v 1.7 2006/03/31 19:41:44 millert Exp $ */ + +/* + * Copyright (c) 2003, 2004 Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <fts.h> +#include <ftw.h> + +int +nftw(const char *path, int (*fn)(const char *, const struct stat *, int, + struct FTW *), int nfds, int ftwflags) +{ + char * const paths[2] = { (char *)path, NULL }; + struct FTW ftw; + FTSENT *cur; + FTS *ftsp; + int error = 0, ftsflags, fnflag, postorder, sverrno; + + /* XXX - nfds is currently unused */ + if (nfds < 1) { + errno = EINVAL; + return (-1); + } + + ftsflags = FTS_COMFOLLOW; + if (!(ftwflags & FTW_CHDIR)) + ftsflags |= FTS_NOCHDIR; + if (ftwflags & FTW_MOUNT) + ftsflags |= FTS_XDEV; + if (ftwflags & FTW_PHYS) + ftsflags |= FTS_PHYSICAL; + else + ftsflags |= FTS_LOGICAL; + postorder = (ftwflags & FTW_DEPTH) != 0; + ftsp = fts_open(paths, ftsflags, NULL); + if (ftsp == NULL) + return (-1); + while ((cur = fts_read(ftsp)) != NULL) { + switch (cur->fts_info) { + case FTS_D: + if (postorder) + continue; + fnflag = FTW_D; + break; + case FTS_DC: + continue; + case FTS_DNR: + fnflag = FTW_DNR; + break; + case FTS_DP: + if (!postorder) + continue; + fnflag = FTW_DP; + break; + case FTS_F: + case FTS_DEFAULT: + fnflag = FTW_F; + break; + case FTS_NS: + case FTS_NSOK: + fnflag = FTW_NS; + break; + case FTS_SL: + fnflag = FTW_SL; + break; + case FTS_SLNONE: + fnflag = FTW_SLN; + break; + default: + error = -1; + goto done; + } + ftw.base = cur->fts_pathlen - cur->fts_namelen; + ftw.level = cur->fts_level; + error = fn(cur->fts_path, cur->fts_statp, fnflag, &ftw); + if (error != 0) + break; + } +done: + sverrno = errno; + if (fts_close(ftsp) != 0 && error == 0) + error = -1; + else + errno = sverrno; + return (error); +} diff --git a/lib/libc/gen/nice.3 b/lib/libc/gen/nice.3 new file mode 100644 index 000000000000..011b4c33effc --- /dev/null +++ b/lib/libc/gen/nice.3 @@ -0,0 +1,94 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd February 28, 2015 +.Dt NICE 3 +.Os +.Sh NAME +.Nm nice +.Nd set program scheduling priority +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn nice "int incr" +.Sh DESCRIPTION +.Bf -symbolic +This interface is obsoleted by +.Xr setpriority 2 . +.Ef +.Pp +The +.Fn nice +function adds +.Fa incr +to the scheduling priority of the process. +The priority is a value in the range -20 to 20. +The default priority is 0; lower priorities cause more favorable scheduling. +Only the super-user may lower priorities. +.Pp +Children inherit the priority of their parent processes via +.Xr fork 2 . +.Sh RETURN VALUES +Upon successful completion, +.Fn nice +returns 0, and +.Va errno +is unchanged. +Otherwise, \-1 is returned, the process' nice value is not changed, and +.Va errno +is set to indicate the error. +.Sh ERRORS +The +.Fn nice +function will fail if: +.Bl -tag -width Er +.It Bq Er EPERM +The +.Fa incr +argument is negative and the caller does not have appropriate privileges. +.El +.Sh SEE ALSO +.Xr nice 1 , +.Xr fork 2 , +.Xr setpriority 2 , +.Xr renice 8 +.Sh STANDARDS +The +.Fn nice +function conforms to +.St -p1003.1-2008 +except for the return value. +This implementation returns 0 upon successful completion but +the standard requires returning the new nice value, +which could be \-1. +.Sh HISTORY +A +.Fn nice +syscall appeared in +.At v6 . diff --git a/lib/libc/gen/nice.c b/lib/libc/gen/nice.c new file mode 100644 index 000000000000..a96d4d06e081 --- /dev/null +++ b/lib/libc/gen/nice.c @@ -0,0 +1,58 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <errno.h> +#include <unistd.h> + +/* + * Backwards compatible nice. + */ +int +nice(int incr) +{ + int saverrno, prio; + + saverrno = errno; + errno = 0; + prio = getpriority(PRIO_PROCESS, 0); + if (prio == -1 && errno != 0) + return (-1); + if (setpriority(PRIO_PROCESS, 0, prio + incr) == -1) { + if (errno == EACCES) + errno = EPERM; + return (-1); + } + errno = saverrno; + return (0); +} diff --git a/lib/libc/gen/nlist.3 b/lib/libc/gen/nlist.3 new file mode 100644 index 000000000000..f4ef59083dab --- /dev/null +++ b/lib/libc/gen/nlist.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 19, 1994 +.Dt NLIST 3 +.Os +.Sh NAME +.Nm nlist +.Nd retrieve symbol table name list from an executable file +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In nlist.h +.Ft int +.Fn nlist "const char *filename" "struct nlist *nl" +.Sh DESCRIPTION +The +.Fn nlist +function +retrieves name list entries from the symbol table of an +executable file (see +.Xr a.out 5 ) . +The argument +.Fa \&nl +is set to reference the +beginning of the list. +The list is preened of binary and invalid data; +if an entry in the +name list is valid, the +.Fa n_type +and +.Fa n_value +for the entry are copied into the list +referenced by +.Fa \&nl . +No other data is copied. +The last entry in the list is always +.Dv NULL . +.Sh RETURN VALUES +The number of invalid entries is returned if successful; otherwise, +if the file +.Fa filename +does not exist or is not executable, the returned value is \-1. +.Sh SEE ALSO +.Xr elf 5 +.Sh HISTORY +A +.Fn nlist +function appeared in +.At v6 . diff --git a/lib/libc/gen/nlist.c b/lib/libc/gen/nlist.c new file mode 100644 index 000000000000..ebf4ae92641a --- /dev/null +++ b/lib/libc/gen/nlist.c @@ -0,0 +1,290 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <sys/file.h> +#include <arpa/inet.h> + +#include <errno.h> +#include <a.out.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include <machine/elf.h> +#include <elf-hints.h> + +int __fdnlist(int, struct nlist *); +int __elf_fdnlist(int, struct nlist *); +int __elf_is_okay__(Elf_Ehdr *); + +int +nlist(const char *name, struct nlist *list) +{ + int fd, n; + + fd = _open(name, O_RDONLY | O_CLOEXEC, 0); + if (fd < 0) + return (-1); + n = __fdnlist(fd, list); + (void)_close(fd); + return (n); +} + +static struct nlist_handlers { + int (*fn)(int fd, struct nlist *list); +} nlist_fn[] = { + { __elf_fdnlist }, +}; + +int +__fdnlist(int fd, struct nlist *list) +{ + int n = -1; + unsigned int i; + + for (i = 0; i < nitems(nlist_fn); i++) { + n = (nlist_fn[i].fn)(fd, list); + if (n != -1) + break; + } + return (n); +} + +#define ISLAST(p) (p->n_un.n_name == 0 || p->n_un.n_name[0] == 0) + +static void elf_sym_to_nlist(struct nlist *, Elf_Sym *, Elf_Shdr *, int); + +/* + * __elf_is_okay__ - Determine if ehdr really + * is ELF and valid for the target platform. + * + * WARNING: This is NOT an ELF ABI function and + * as such its use should be restricted. + */ +int +__elf_is_okay__(Elf_Ehdr *ehdr) +{ + int retval = 0; + /* + * We need to check magic, class size, endianess, + * and version before we look at the rest of the + * Elf_Ehdr structure. These few elements are + * represented in a machine independent fashion. + */ + if (IS_ELF(*ehdr) && + ehdr->e_ident[EI_CLASS] == ELF_TARG_CLASS && + ehdr->e_ident[EI_DATA] == ELF_TARG_DATA && + ehdr->e_ident[EI_VERSION] == ELF_TARG_VER) { + + /* Now check the machine dependant header */ + if (ehdr->e_machine == ELF_TARG_MACH && + ehdr->e_version == ELF_TARG_VER) + retval = 1; + } + return retval; +} + +int +__elf_fdnlist(int fd, struct nlist *list) +{ + struct nlist *p; + Elf_Off symoff = 0, symstroff = 0; + Elf_Size symsize = 0, symstrsize = 0; + Elf_Ssize cc, i; + int nent = -1; + int errsave; + Elf_Sym sbuf[1024]; + Elf_Sym *s; + Elf_Ehdr ehdr; + char *strtab = NULL; + Elf_Shdr *shdr = NULL; + Elf_Size shdr_size; + void *base; + struct stat st; + + /* Make sure obj is OK */ + if (lseek(fd, (off_t)0, SEEK_SET) == -1 || + _read(fd, &ehdr, sizeof(Elf_Ehdr)) != sizeof(Elf_Ehdr) || + !__elf_is_okay__(&ehdr) || + _fstat(fd, &st) < 0) + return (-1); + + /* calculate section header table size */ + shdr_size = ehdr.e_shentsize * ehdr.e_shnum; + + /* Make sure it's not too big to mmap */ + if (shdr_size > SIZE_T_MAX) { + errno = EFBIG; + return (-1); + } + + /* mmap section header table */ + base = mmap(NULL, (size_t)shdr_size, PROT_READ, MAP_PRIVATE, fd, + (off_t)ehdr.e_shoff); + if (base == MAP_FAILED) + return (-1); + shdr = (Elf_Shdr *)base; + + /* + * Find the symbol table entry and it's corresponding + * string table entry. Version 1.1 of the ABI states + * that there is only one symbol table but that this + * could change in the future. + */ + for (i = 0; i < ehdr.e_shnum; i++) { + if (shdr[i].sh_type == SHT_SYMTAB) { + symoff = shdr[i].sh_offset; + symsize = shdr[i].sh_size; + symstroff = shdr[shdr[i].sh_link].sh_offset; + symstrsize = shdr[shdr[i].sh_link].sh_size; + break; + } + } + + /* Check for files too large to mmap. */ + if (symstrsize > SIZE_T_MAX) { + errno = EFBIG; + goto done; + } + /* + * Map string table into our address space. This gives us + * an easy way to randomly access all the strings, without + * making the memory allocation permanent as with malloc/free + * (i.e., munmap will return it to the system). + */ + base = mmap(NULL, (size_t)symstrsize, PROT_READ, MAP_PRIVATE, fd, + (off_t)symstroff); + if (base == MAP_FAILED) + goto done; + strtab = (char *)base; + + /* + * clean out any left-over information for all valid entries. + * Type and value defined to be 0 if not found; historical + * versions cleared other and desc as well. Also figure out + * the largest string length so don't read any more of the + * string table than we have to. + * + * XXX clearing anything other than n_type and n_value violates + * the semantics given in the man page. + */ + nent = 0; + for (p = list; !ISLAST(p); ++p) { + p->n_type = 0; + p->n_other = 0; + p->n_desc = 0; + p->n_value = 0; + ++nent; + } + + /* Don't process any further if object is stripped. */ + if (symoff == 0) + goto done; + + if (lseek(fd, (off_t) symoff, SEEK_SET) == -1) { + nent = -1; + goto done; + } + + while (symsize > 0 && nent > 0) { + cc = MIN(symsize, sizeof(sbuf)); + if (_read(fd, sbuf, cc) != cc) + break; + symsize -= cc; + for (s = sbuf; cc > 0 && nent > 0; ++s, cc -= sizeof(*s)) { + char *name; + struct nlist *p; + + name = strtab + s->st_name; + if (name[0] == '\0') + continue; + for (p = list; !ISLAST(p); p++) { + if ((p->n_un.n_name[0] == '_' && + strcmp(name, p->n_un.n_name+1) == 0) + || strcmp(name, p->n_un.n_name) == 0) { + elf_sym_to_nlist(p, s, shdr, + ehdr.e_shnum); + if (--nent <= 0) + break; + } + } + } + } + done: + errsave = errno; + if (strtab != NULL) + munmap(strtab, symstrsize); + if (shdr != NULL) + munmap(shdr, shdr_size); + errno = errsave; + return (nent); +} + +/* + * Convert an Elf_Sym into an nlist structure. This fills in only the + * n_value and n_type members. + */ +static void +elf_sym_to_nlist(struct nlist *nl, Elf_Sym *s, Elf_Shdr *shdr, int shnum) +{ + nl->n_value = s->st_value; + + switch (s->st_shndx) { + case SHN_UNDEF: + case SHN_COMMON: + nl->n_type = N_UNDF; + break; + case SHN_ABS: + nl->n_type = ELF_ST_TYPE(s->st_info) == STT_FILE ? + N_FN : N_ABS; + break; + default: + if (s->st_shndx >= shnum) + nl->n_type = N_UNDF; + else { + Elf_Shdr *sh = shdr + s->st_shndx; + + nl->n_type = sh->sh_type == SHT_PROGBITS ? + (sh->sh_flags & SHF_WRITE ? N_DATA : N_TEXT) : + (sh->sh_type == SHT_NOBITS ? N_BSS : N_UNDF); + } + break; + } + + if (ELF_ST_BIND(s->st_info) == STB_GLOBAL || + ELF_ST_BIND(s->st_info) == STB_WEAK) + nl->n_type |= N_EXT; +} diff --git a/lib/libc/gen/nrand48.c b/lib/libc/gen/nrand48.c new file mode 100644 index 000000000000..f6f4e231105c --- /dev/null +++ b/lib/libc/gen/nrand48.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +long +nrand48(unsigned short xseed[3]) +{ + uint48 tmp; + + DORAND48(tmp, xseed); + return ((tmp >> 17) & 0x7fffffff); +} diff --git a/lib/libc/gen/opendir.c b/lib/libc/gen/opendir.c new file mode 100644 index 000000000000..08d9eb10eaa2 --- /dev/null +++ b/lib/libc/gen/opendir.c @@ -0,0 +1,47 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <dirent.h> +#include "un-namespace.h" + +#include "gen-private.h" +#include "telldir.h" + +/* + * Open a directory. + */ +DIR * +opendir(const char *name) +{ + + return (__opendir2(name, DTF_HIDEW | DTF_NODUP)); +} diff --git a/lib/libc/gen/opendir2.c b/lib/libc/gen/opendir2.c new file mode 100644 index 000000000000..c5c2e662efd8 --- /dev/null +++ b/lib/libc/gen/opendir2.c @@ -0,0 +1,337 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "gen-private.h" +#include "telldir.h" + +DIR * +__opendir2(const char *name, int flags) +{ + int fd; + DIR *dir; + int saved_errno; + + if ((flags & (__DTF_READALL | __DTF_SKIPREAD)) != 0) + return (NULL); + if ((fd = _open(name, O_DIRECTORY | O_RDONLY | O_CLOEXEC)) == -1) + return (NULL); + + dir = __opendir_common(fd, flags, false); + if (dir == NULL) { + saved_errno = errno; + _close(fd); + errno = saved_errno; + } + return (dir); +} + +static int +opendir_compar(const void *p1, const void *p2) +{ + + return (strcmp((*(const struct dirent * const *)p1)->d_name, + (*(const struct dirent * const *)p2)->d_name)); +} + +/* + * For a directory at the top of a unionfs stack, the entire directory's + * contents are read and cached locally until the next call to rewinddir(). + * For the fdopendir() case, the initial seek position must be preserved. + * For rewinddir(), the full directory should always be re-read from the + * beginning. + * + * If an error occurs, the existing buffer and state of 'dirp' is left + * unchanged. + */ +bool +_filldir(DIR *dirp, bool use_current_pos) +{ + struct dirent **dpv; + char *buf, *ddptr, *ddeptr; + off_t pos; + int fd2, incr, len, n, saved_errno, space; + + len = 0; + space = 0; + buf = NULL; + ddptr = NULL; + + /* + * Use the system page size if that is a multiple of DIRBLKSIZ. + * Hopefully this can be a big win someday by allowing page + * trades to user space to be done by _getdirentries(). + */ + incr = getpagesize(); + if ((incr % DIRBLKSIZ) != 0) + incr = DIRBLKSIZ; + + /* + * The strategy here is to read all the directory + * entries into a buffer, sort the buffer, and + * remove duplicate entries by setting the inode + * number to zero. + * + * We reopen the directory because _getdirentries() + * on a MNT_UNION mount modifies the open directory, + * making it refer to the lower directory after the + * upper directory's entries are exhausted. + * This would otherwise break software that uses + * the directory descriptor for fchdir or *at + * functions, such as fts.c. + */ + if ((fd2 = _openat(dirp->dd_fd, ".", O_RDONLY | O_CLOEXEC)) == -1) + return (false); + + if (use_current_pos) { + pos = lseek(dirp->dd_fd, 0, SEEK_CUR); + if (pos == -1 || lseek(fd2, pos, SEEK_SET) == -1) { + saved_errno = errno; + _close(fd2); + errno = saved_errno; + return (false); + } + } + + do { + /* + * Always make at least DIRBLKSIZ bytes + * available to _getdirentries + */ + if (space < DIRBLKSIZ) { + space += incr; + len += incr; + buf = reallocf(buf, len); + if (buf == NULL) { + saved_errno = errno; + _close(fd2); + errno = saved_errno; + return (false); + } + ddptr = buf + (len - space); + } + + n = _getdirentries(fd2, ddptr, space, &dirp->dd_seek); + if (n > 0) { + ddptr += n; + space -= n; + } + if (n < 0) { + saved_errno = errno; + _close(fd2); + errno = saved_errno; + return (false); + } + } while (n > 0); + _close(fd2); + + ddeptr = ddptr; + + /* + * There is now a buffer full of (possibly) duplicate + * names. + */ + dirp->dd_buf = buf; + + /* + * Go round this loop twice... + * + * Scan through the buffer, counting entries. + * On the second pass, save pointers to each one. + * Then sort the pointers and remove duplicate names. + */ + for (dpv = NULL;;) { + n = 0; + ddptr = buf; + while (ddptr < ddeptr) { + struct dirent *dp; + + dp = (struct dirent *) ddptr; + if ((long)dp & 03L) + break; + if ((dp->d_reclen <= 0) || + (dp->d_reclen > (ddeptr + 1 - ddptr))) + break; + ddptr += dp->d_reclen; + if (dp->d_fileno) { + if (dpv) + dpv[n] = dp; + n++; + } + } + + if (dpv) { + struct dirent *xp; + + /* + * This sort must be stable. + */ + mergesort(dpv, n, sizeof(*dpv), opendir_compar); + + dpv[n] = NULL; + xp = NULL; + + /* + * Scan through the buffer in sort order, + * zapping the inode number of any + * duplicate names. + */ + for (n = 0; dpv[n]; n++) { + struct dirent *dp = dpv[n]; + + if ((xp == NULL) || + strcmp(dp->d_name, xp->d_name)) { + xp = dp; + } else { + dp->d_fileno = 0; + } + if (dp->d_type == DT_WHT && + (dirp->dd_flags & DTF_HIDEW)) + dp->d_fileno = 0; + } + + free(dpv); + break; + } else { + dpv = malloc((n+1) * sizeof(struct dirent *)); + if (dpv == NULL) + break; + } + } + + dirp->dd_len = len; + dirp->dd_size = ddptr - dirp->dd_buf; + return (true); +} + +/* + * Return true if the file descriptor is associated with a file from a + * union file system or from a file system mounted with the union flag. + */ +static bool +is_unionstack(int fd) +{ + /* + * This call shouldn't fail, but if it does, just assume that the + * answer is no. + */ + return (_fcntl(fd, F_ISUNIONSTACK, 0) > 0); +} + +/* + * Common routine for opendir(3), __opendir2(3) and fdopendir(3). + */ +DIR * +__opendir_common(int fd, int flags, bool use_current_pos) +{ + DIR *dirp; + ssize_t ret; + int incr; + int saved_errno; + bool unionstack; + + if ((dirp = malloc(sizeof(DIR) + sizeof(struct _telldir))) == NULL) + return (NULL); + + dirp->dd_buf = NULL; + dirp->dd_fd = fd; + dirp->dd_flags = flags; + dirp->dd_loc = 0; + dirp->dd_lock = NULL; + dirp->dd_td = (struct _telldir *)((char *)dirp + sizeof(DIR)); + LIST_INIT(&dirp->dd_td->td_locq); + dirp->dd_td->td_loccnt = 0; + dirp->dd_compat_de = NULL; + + /* + * Use the system page size if that is a multiple of DIRBLKSIZ. + * Hopefully this can be a big win someday by allowing page + * trades to user space to be done by _getdirentries(). + */ + incr = getpagesize(); + if ((incr % DIRBLKSIZ) != 0) + incr = DIRBLKSIZ; + + /* + * Determine whether this directory is the top of a union stack. + */ + unionstack = false; + if (flags & DTF_NODUP) { + unionstack = is_unionstack(fd); + } + + if (unionstack) { + if (!_filldir(dirp, use_current_pos)) + goto fail; + dirp->dd_flags |= __DTF_READALL; + } else { + dirp->dd_len = incr; + dirp->dd_buf = malloc(dirp->dd_len); + if (dirp->dd_buf == NULL) + goto fail; + if (use_current_pos) { + /* + * Read the first batch of directory entries + * to prime dd_seek. This also checks if the + * fd passed to fdopendir() is a directory. + */ + ret = _getdirentries(dirp->dd_fd, + dirp->dd_buf, dirp->dd_len, &dirp->dd_seek); + if (ret < 0) + goto fail; + dirp->dd_size = (size_t)ret; + dirp->dd_flags |= __DTF_SKIPREAD; + } else { + dirp->dd_size = 0; + dirp->dd_seek = 0; + } + } + + return (dirp); + +fail: + saved_errno = errno; + free(dirp->dd_buf); + free(dirp); + errno = saved_errno; + return (NULL); +} diff --git a/lib/libc/gen/pause.3 b/lib/libc/gen/pause.3 new file mode 100644 index 000000000000..6b17ae10777d --- /dev/null +++ b/lib/libc/gen/pause.3 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 3, 2022 +.Dt PAUSE 3 +.Os +.Sh NAME +.Nm pause +.Nd stop until signal +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn pause void +.Sh DESCRIPTION +.Sy Pause is made obsolete by +.Xr sigsuspend 2 . +.Pp +The +.Fn pause +function +forces a process to pause until +a signal is received from either the +.Xr kill 2 +function +or an interval timer. +(See +.Xr setitimer 2 . ) +Upon termination of a signal handler started during a +.Fn pause , +the +.Fn pause +call will return. +.Sh RETURN VALUES +Always returns \-1. +.Sh ERRORS +The +.Fn pause +function +always returns: +.Bl -tag -width Er +.It Bq Er EINTR +The call was interrupted. +.El +.Sh SEE ALSO +.Xr kill 2 , +.Xr select 2 , +.Xr sigsuspend 2 +.Sh HISTORY +A +.Fn pause +system call first appeared in the Programmer's Workbench (PWB/UNIX) +and was then ported to +.At v7 . +It was reimplemeted as a wrapper around the +.Fn sigpause +and +.Fn sigblock +system calls in +.Bx 4.2 , +and around the +.Xr sigsuspend 2 +and +.Xr sigprocmask 2 +system calls in +.Bx 4.3 Reno . diff --git a/lib/libc/gen/pause.c b/lib/libc/gen/pause.c new file mode 100644 index 000000000000..38aed9da7439 --- /dev/null +++ b/lib/libc/gen/pause.c @@ -0,0 +1,53 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <signal.h> +#include <unistd.h> + +#include "libc_private.h" + +int __pause(void); + +/* + * Backwards compatible pause. + */ +int +__pause(void) +{ + sigset_t oset; + + if (sigprocmask(SIG_BLOCK, NULL, &oset) == -1) + return (-1); + return (sigsuspend(&oset)); +} + +__weak_reference(__pause, pause); +__weak_reference(__pause, _pause); diff --git a/lib/libc/gen/pmadvise.c b/lib/libc/gen/pmadvise.c new file mode 100644 index 000000000000..19525c939c26 --- /dev/null +++ b/lib/libc/gen/pmadvise.c @@ -0,0 +1,23 @@ +/* + * The contents of this file are in the public domain. + * Written by Garrett A. Wollman, 2000-10-07. + * + */ + +#include <sys/mman.h> +#include <errno.h> + +int +posix_madvise(void *address, size_t size, int how) +{ + int ret, saved_errno; + + saved_errno = errno; + if (madvise(address, size, how) == -1) { + ret = errno; + errno = saved_errno; + } else { + ret = 0; + } + return (ret); +} diff --git a/lib/libc/gen/popen.3 b/lib/libc/gen/popen.3 new file mode 100644 index 000000000000..bae37eed14cf --- /dev/null +++ b/lib/libc/gen/popen.3 @@ -0,0 +1,199 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 20, 2013 +.Dt POPEN 3 +.Os +.Sh NAME +.Nm popen , +.Nm pclose +.Nd process +.Tn I/O +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdio.h +.Ft FILE * +.Fn popen "const char *command" "const char *type" +.Ft int +.Fn pclose "FILE *stream" +.Sh DESCRIPTION +The +.Fn popen +function +.Dq opens +a process by creating a bidirectional pipe +forking, +and invoking the shell. +Any streams opened by previous +.Fn popen +calls in the parent process are closed in the new child process. +Historically, +.Fn popen +was implemented with a unidirectional pipe; +hence many implementations of +.Fn popen +only allow the +.Fa type +argument to specify reading or writing, not both. +Since +.Fn popen +is now implemented using a bidirectional pipe, the +.Fa type +argument may request a bidirectional data flow. +The +.Fa type +argument is a pointer to a null-terminated string +which must be +.Ql r +for reading, +.Ql w +for writing, or +.Ql r+ +for reading and writing. +.Pp +A letter +.Ql e +may be appended to that to request that the underlying file descriptor +be set close-on-exec. +.Pp +The +.Fa command +argument is a pointer to a null-terminated string +containing a shell command line. +This command is passed to +.Pa /bin/sh +using the +.Fl c +flag; interpretation, if any, is performed by the shell. +.Pp +The return value from +.Fn popen +is a normal standard +.Tn I/O +stream in all respects +save that it must be closed with +.Fn pclose +rather than +.Fn fclose . +Writing to such a stream +writes to the standard input of the command; +the command's standard output is the same as that of the process that called +.Fn popen , +unless this is altered by the command itself. +Conversely, reading from a +.Dq popened +stream reads the command's standard output, and +the command's standard input is the same as that of the process that called +.Fn popen . +.Pp +Note that output +.Fn popen +streams are fully buffered by default. +.Pp +The +.Fn pclose +function waits for the associated process to terminate +and returns the exit status of the command +as returned by +.Xr wait4 2 . +.Sh RETURN VALUES +The +.Fn popen +function returns +.Dv NULL +if the +.Xr fork 2 +or +.Xr pipe 2 +calls fail, +or if it cannot allocate memory. +.Pp +The +.Fn pclose +function +returns \-1 if +.Fa stream +is not associated with a +.Dq popened +command, if +.Fa stream +already +.Dq pclosed , +or if +.Xr wait4 2 +returns an error. +.Sh ERRORS +The +.Fn popen +function does not reliably set +.Va errno . +.Sh SEE ALSO +.Xr sh 1 , +.Xr fork 2 , +.Xr pipe 2 , +.Xr wait4 2 , +.Xr fclose 3 , +.Xr fflush 3 , +.Xr fopen 3 , +.Xr stdio 3 , +.Xr system 3 +.Sh HISTORY +A +.Fn popen +and a +.Fn pclose +function appeared in +.At v7 . +.Pp +Bidirectional functionality was added in +.Fx 2.2.6 . +.Sh BUGS +Since the standard input of a command opened for reading +shares its seek offset with the process that called +.Fn popen , +if the original process has done a buffered read, +the command's input position may not be as expected. +Similarly, the output from a command opened for writing +may become intermingled with that of the original process. +The latter can be avoided by calling +.Xr fflush 3 +before +.Fn popen . +.Pp +Failure to execute the shell +is indistinguishable from the shell's failure to execute command, +or an immediate exit of the command. +The only hint is an exit status of 127. +.Pp +The +.Fn popen +function +always calls +.Xr sh 1 , +never calls +.Xr csh 1 . diff --git a/lib/libc/gen/popen.c b/lib/libc/gen/popen.c new file mode 100644 index 000000000000..db6b91d08af6 --- /dev/null +++ b/lib/libc/gen/popen.c @@ -0,0 +1,223 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software written by Ken Arnold and + * published in UNIX Review, Vol. 6, No. 8. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/wait.h> + +#include <signal.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <paths.h> +#include <pthread.h> +#include "un-namespace.h" +#include "libc_private.h" + +struct pid { + SLIST_ENTRY(pid) next; + FILE *fp; + pid_t pid; +}; +static SLIST_HEAD(, pid) pidlist = SLIST_HEAD_INITIALIZER(pidlist); +static pthread_mutex_t pidlist_mutex = PTHREAD_MUTEX_INITIALIZER; + +#define THREAD_LOCK() if (__isthreaded) _pthread_mutex_lock(&pidlist_mutex) +#define THREAD_UNLOCK() if (__isthreaded) _pthread_mutex_unlock(&pidlist_mutex) + +FILE * +popen(const char *command, const char *type) +{ + struct pid *cur; + FILE *iop; + int pdes[2], pid, twoway, cloexec; + int pdes_unused_in_parent; + char *argv[4]; + struct pid *p; + + cloexec = strchr(type, 'e') != NULL; + /* + * Lite2 introduced two-way popen() pipes using _socketpair(). + * FreeBSD's pipe() is bidirectional, so we use that. + */ + if (strchr(type, '+')) { + twoway = 1; + type = "r+"; + } else { + twoway = 0; + if ((*type != 'r' && *type != 'w') || + (type[1] && (type[1] != 'e' || type[2]))) + return (NULL); + } + if (pipe2(pdes, O_CLOEXEC) < 0) + return (NULL); + + if ((cur = malloc(sizeof(struct pid))) == NULL) { + (void)_close(pdes[0]); + (void)_close(pdes[1]); + return (NULL); + } + + if (*type == 'r') { + iop = fdopen(pdes[0], type); + pdes_unused_in_parent = pdes[1]; + } else { + iop = fdopen(pdes[1], type); + pdes_unused_in_parent = pdes[0]; + } + if (iop == NULL) { + (void)_close(pdes[0]); + (void)_close(pdes[1]); + free(cur); + return (NULL); + } + + argv[0] = "sh"; + argv[1] = "-c"; + argv[2] = (char *)command; + argv[3] = NULL; + + THREAD_LOCK(); + switch (pid = vfork()) { + case -1: /* Error. */ + THREAD_UNLOCK(); + /* + * The _close() closes the unused end of pdes[], while + * the fclose() closes the used end of pdes[], *and* cleans + * up iop. + */ + (void)_close(pdes_unused_in_parent); + free(cur); + (void)fclose(iop); + return (NULL); + /* NOTREACHED */ + case 0: /* Child. */ + if (*type == 'r') { + /* + * The _dup2() to STDIN_FILENO is repeated to avoid + * writing to pdes[1], which might corrupt the + * parent's copy. This isn't good enough in + * general, since the _exit() is no return, so + * the compiler is free to corrupt all the local + * variables. + */ + if (pdes[1] != STDOUT_FILENO) { + (void)_dup2(pdes[1], STDOUT_FILENO); + if (twoway) + (void)_dup2(STDOUT_FILENO, STDIN_FILENO); + } else if (twoway && (pdes[1] != STDIN_FILENO)) { + (void)_dup2(pdes[1], STDIN_FILENO); + (void)_fcntl(pdes[1], F_SETFD, 0); + } else + (void)_fcntl(pdes[1], F_SETFD, 0); + } else { + if (pdes[0] != STDIN_FILENO) { + (void)_dup2(pdes[0], STDIN_FILENO); + } else + (void)_fcntl(pdes[0], F_SETFD, 0); + } + SLIST_FOREACH(p, &pidlist, next) + (void)_close(fileno(p->fp)); + _execve(_PATH_BSHELL, argv, environ); + _exit(127); + /* NOTREACHED */ + } + THREAD_UNLOCK(); + + /* Parent. */ + (void)_close(pdes_unused_in_parent); + + /* Link into list of file descriptors. */ + cur->fp = iop; + cur->pid = pid; + THREAD_LOCK(); + SLIST_INSERT_HEAD(&pidlist, cur, next); + THREAD_UNLOCK(); + + /* + * To guard against undesired fd passing with concurrent calls, + * only clear the close-on-exec flag after linking the file into + * the list which will cause an explicit close. + */ + if (!cloexec) + (void)_fcntl(fileno(iop), F_SETFD, 0); + + return (iop); +} + +/* + * pclose -- + * Pclose returns -1 if stream is not associated with a `popened' command, + * if already `pclosed', or waitpid returns an error. + */ +int +pclose(FILE *iop) +{ + struct pid *cur, *last = NULL; + int pstat; + pid_t pid; + + /* + * Find the appropriate file pointer and remove it from the list. + */ + THREAD_LOCK(); + SLIST_FOREACH(cur, &pidlist, next) { + if (cur->fp == iop) + break; + last = cur; + } + if (cur == NULL) { + THREAD_UNLOCK(); + return (-1); + } + if (last == NULL) + SLIST_REMOVE_HEAD(&pidlist, next); + else + SLIST_REMOVE_AFTER(last, next); + THREAD_UNLOCK(); + + (void)fclose(iop); + + do { + pid = _wait4(cur->pid, &pstat, 0, (struct rusage *)0); + } while (pid == -1 && errno == EINTR); + + free(cur); + + return (pid == -1 ? -1 : pstat); +} diff --git a/lib/libc/gen/posix_spawn.3 b/lib/libc/gen/posix_spawn.3 new file mode 100644 index 000000000000..278fee88463a --- /dev/null +++ b/lib/libc/gen/posix_spawn.3 @@ -0,0 +1,492 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 4, 2024 +.Dt POSIX_SPAWN 3 +.Os +.Sh NAME +.Nm posix_spawn , +.Nm posix_spawnp +.Nd "spawn a process" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fo posix_spawn +.Fa "pid_t *restrict pid" +.Fa "const char *restrict path" +.Fa "const posix_spawn_file_actions_t *file_actions" +.Fa "const posix_spawnattr_t *restrict attrp" +.Fa "char *const argv[restrict]" +.Fa "char *const envp[restrict]" +.Fc +.Ft int +.Fo posix_spawnp +.Fa "pid_t *restrict pid" +.Fa "const char *restrict file" +.Fa "const posix_spawn_file_actions_t *file_actions" +.Fa "const posix_spawnattr_t *restrict attrp" +.Fa "char *const argv[restrict]" +.Fa "char *const envp[restrict]" +.Fc +.Sh DESCRIPTION +The +.Fn posix_spawn +and +.Fn posix_spawnp +functions create a new process (child process) from the specified +process image. +The new process image is constructed from a regular executable +file called the new process image file. +.Pp +When a C program is executed as the result of this call, it is +entered as a C-language function call as follows: +.Bd -literal -offset indent +int main(int argc, char *argv[]); +.Ed +.Pp +where +.Fa argc +is the argument count and +.Fa argv +is an array of character pointers to the arguments themselves. +In addition, the variable: +.Bd -literal -offset indent +extern char **environ; +.Ed +.Pp +points to an array of character pointers to +the environment strings. +.Pp +The argument +.Fa argv +is an array of character pointers to null-terminated +strings. +The last member of this array is a null pointer and is not counted +in +.Fa argc . +These strings constitute the argument list available to the new process +image. +The value in +.Fa argv Ns [0] +should point to +a filename that is associated with the process image being started by +the +.Fn posix_spawn +or +.Fn posix_spawnp +function. +.Pp +The argument +.Fa envp +is an array of character pointers to null-terminated strings. +These strings constitute the environment for the new process image. +The environment array is terminated by a null pointer. +.Pp +The +.Fa path +argument to +.Fn posix_spawn +is a pathname that identifies the new process image file to execute. +.Pp +The +.Fa file +parameter to +.Fn posix_spawnp +is used to construct a pathname that identifies the new process +image file. +If the file parameter contains a slash character, the file parameter +is used as the pathname for the new process image file. +Otherwise, the path prefix for this file is obtained by a search +of the directories passed as the environment variable +.Dq Ev PATH . +If this variable is not specified, +the default path is set according to the +.Dv _PATH_DEFPATH +definition in +.In paths.h , +which is set to +.Dq Ev /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin . +.Pp +If +.Fa file_actions +is a null pointer, then file descriptors open in the +calling process remain open in the child process, except for those +whose close-on-exec flag +.Dv FD_CLOEXEC +is set (see +.Fn fcntl ) . +For those +file descriptors that remain open, all attributes of the corresponding +open file descriptions, including file locks (see +.Fn fcntl ) , +remain unchanged. +.Pp +If +.Fa file_actions +is not NULL, then the file descriptors open in the child process are +those open in the calling process as modified by the spawn file +actions object pointed to by +.Fa file_actions +and the +.Dv FD_CLOEXEC +flag of each remaining open file descriptor after the spawn file actions +have been processed. +The effective order of processing the spawn file actions are: +.Bl -enum +.It +The set of open file descriptors for the child process initially +are the same set as is open for the calling process. +All attributes of the corresponding open file descriptions, including +file locks (see +.Fn fcntl ) , +remain unchanged. +.It +The signal mask, signal default actions, and the effective user and +group IDs for the child process are changed as specified in the +attributes object referenced by +.Fa attrp . +.It +The file actions specified by the spawn file actions object are +performed in the order in which they were added to the spawn file +actions object. +.It +Any file descriptor that has its +.Dv FD_CLOEXEC +flag set (see +.Fn fcntl ) +is closed. +.El +.Pp +The +.Vt posix_spawnattr_t +spawn attributes object type is defined in +.In spawn.h . +It contains the attributes defined below. +.Pp +If the +.Dv POSIX_SPAWN_SETPGROUP +flag is set in the spawn-flags attribute of the object referenced by +.Fa attrp , +and the spawn-pgroup attribute of the same object is non-zero, then the +child's process group is as specified in the spawn-pgroup +attribute of the object referenced by +.Fa attrp . +.Pp +As a special case, if the +.Dv POSIX_SPAWN_SETPGROUP +flag is set in the spawn-flags attribute of the object referenced by +.Fa attrp , +and the spawn-pgroup attribute of the same object is set to zero, then +the child is in a new process group with a process group ID equal +to its process ID. +.Pp +If the +.Dv POSIX_SPAWN_SETPGROUP +flag is not set in the spawn-flags attribute of the object referenced by +.Fa attrp , +the new child process inherits the parent's process group. +.Pp +If the +.Dv POSIX_SPAWN_SETSCHEDPARAM +flag is set in the spawn-flags attribute of the object referenced by +.Fa attrp , +but +.Dv POSIX_SPAWN_SETSCHEDULER +is not set, the new process image initially has the scheduling +policy of the calling process with the scheduling parameters specified +in the spawn-schedparam attribute of the object referenced by +.Fa attrp . +.Pp +If the +.Dv POSIX_SPAWN_SETSCHEDULER +flag is set in the spawn-flags attribute of the object referenced by +.Fa attrp +(regardless of the setting of the +.Dv POSIX_SPAWN_SETSCHEDPARAM +flag), the new process image initially has the scheduling policy +specified in the spawn-schedpolicy attribute of the object referenced by +.Fa attrp +and the scheduling parameters specified in the spawn-schedparam +attribute of the same object. +.Pp +The +.Dv POSIX_SPAWN_RESETIDS +flag in the spawn-flags attribute of the object referenced by +.Fa attrp +governs the effective user ID of the child process. +If this flag is not set, the child process inherits the parent +process' effective user ID. +If this flag is set, the child process' effective user ID is reset +to the parent's real user ID. +In either case, if the set-user-ID mode bit of the new process image +file is set, the effective user ID of the child process becomes +that file's owner ID before the new process image begins execution. +.Pp +The +.Dv POSIX_SPAWN_RESETIDS +flag in the spawn-flags attribute of the object referenced by +.Fa attrp +also governs the effective group ID of the child process. +If this flag is not set, the child process inherits the parent +process' effective group ID. +If this flag is set, the child process' effective group ID is +reset to the parent's real group ID. +In either case, if the set-group-ID mode bit of the new process image +file is set, the effective group ID of the child process becomes +that file's group ID before the new process image begins execution. +.Pp +If the +.Dv POSIX_SPAWN_SETSIGMASK +flag is set in the spawn-flags attribute of the object referenced by +.Fa attrp , +the child process initially has the signal mask specified in the +spawn-sigmask attribute of the object referenced by +.Fa attrp . +.Pp +If the +.Dv POSIX_SPAWN_SETSIGDEF +flag is set in the spawn-flags attribute of the object referenced by +.Fa attrp , +the signals specified in the spawn-sigdefault attribute of the same +object are set to their default actions in the child process. +Signals set to the default action in the parent process are set to +the default action in the child process. +.Pp +Signals set to be caught by the calling process are set to the +default action in the child process. +.Pp +Signals set to be ignored by the calling process image are set to +be ignored by the child process, unless otherwise specified by the +.Dv POSIX_SPAWN_SETSIGDEF +flag being set in the spawn-flags attribute of the object referenced by +.Fa attrp +and the signals being indicated in the spawn-sigdefault attribute +of the object referenced by +.Fa attrp . +.Pp +The Address Space Layout Randomization for the newly spawned process +can be disabled by specifying the +.Dv POSIX_SPAWN_DISABLE_ASLR_NP +flag in the spawn-flags attribute. +This setting is inherited by future children of the child as well. +See +.Xr procctl 2 +for more details. +.Pp +If the value of the +.Fa attrp +pointer is NULL, then the default values are used. +.Pp +All process attributes, other than those influenced by the attributes +set in the object referenced by +.Fa attrp +as specified above or by the file descriptor manipulations specified in +.Fa file_actions , +appear in the new process image as though +.Fn vfork +had been called to create a child process and then +.Fn execve +had been called by the child process to execute the new process image. +.Pp +The implementation uses +.Fn vfork , +thus the fork handlers are not run when +.Fn posix_spawn +or +.Fn posix_spawnp +is called. +.Sh RETURN VALUES +Upon successful completion, +.Fn posix_spawn +and +.Fn posix_spawnp +return the process ID of the child process to the parent process, +in the variable pointed to by a non-NULL +.Fa pid +argument, and return zero as the function return value. +Otherwise, no child process is created, no value is stored into +the variable pointed to by +.Fa pid , +and an error number is returned as the function return value to +indicate the error. +If the +.Fa pid +argument is a null pointer, the process ID of the child is not returned +to the caller. +.Sh ERRORS +.Bl -enum +.It +If +.Fn posix_spawn +and +.Fn posix_spawnp +fail for any of the reasons that would cause +.Fn vfork +or one of the +.Nm exec +to fail, an error value is returned as described by +.Fn vfork +and +.Nm exec , +respectively (or, if the error occurs after the calling process successfully +returns, the child process exits with exit status 127). +.It +If +.Nm POSIX_SPAWN_SETPGROUP +is set in the spawn-flags attribute of the object referenced by attrp, and +.Fn posix_spawn +or +.Fn posix_spawnp +fails while changing the child's process group, an error value is returned as +described by +.Fn setpgid +(or, if the error occurs after the calling process successfully returns, +the child process exits with exit status 127). +.It +If +.Nm POSIX_SPAWN_SETSCHEDPARAM +is set and +.Nm POSIX_SPAWN_SETSCHEDULER +is not set in the spawn-flags attribute of the object referenced by attrp, then +if +.Fn posix_spawn +or +.Fn posix_spawnp +fails for any of the reasons that would cause +.Fn sched_setparam +to fail, an error value is returned as described by +.Fn sched_setparam +(or, if the error occurs after the calling process successfully returns, the +child process exits with exit status 127). +.It +If +.Nm POSIX_SPAWN_SETSCHEDULER +is set in the spawn-flags attribute of the object referenced by attrp, and if +.Fn posix_spawn +or +.Fn posix_spawnp +fails for any of the reasons that would cause +.Fn sched_setscheduler +to fail, an error value is returned as described by +.Fn sched_setscheduler +(or, if the error occurs after the calling process successfully returns, +the child process exits with exit status 127). +.It +If the +.Fa file_actions +argument is not NULL, and specifies any dup2 or open actions to be +performed, and if +.Fn posix_spawn +or +.Fn posix_spawnp +fails for any of the reasons that would cause +.Fn dup2 +or +.Fn open +to fail, an error value is returned as described by +.Fn dup2 +and +.Fn open , +respectively (or, if the error occurs after the calling process successfully +returns, the child process exits with exit status 127). An open file action +may, by itself, result in any of the errors described by +.Fn dup2 , +in addition to those described by +.Fn open . +This implementation ignores any errors from +.Fn close , +including trying to close a descriptor that is not open. +The ignore extends to any errors from individual file descriptors +.Fn close +executed as part of the +.Fn closefrom +action. +.El +.Sh SEE ALSO +.Xr close 2 , +.Xr dup2 2 , +.Xr execve 2 , +.Xr fcntl 2 , +.Xr open 2 , +.Xr procctl 2 , +.Xr sched_setparam 2 , +.Xr sched_setscheduler 2 , +.Xr setpgid 2 , +.Xr vfork 2 , +.Xr posix_spawn_file_actions_addchdir_np 3 , +.Xr posix_spawn_file_actions_addclose 3 , +.Xr posix_spawn_file_actions_addclosefrom_np 3 , +.Xr posix_spawn_file_actions_adddup2 3 , +.Xr posix_spawn_file_actions_addfchdir_np 3 , +.Xr posix_spawn_file_actions_addopen 3 , +.Xr posix_spawn_file_actions_destroy 3 , +.Xr posix_spawn_file_actions_init 3 , +.Xr posix_spawnattr_destroy 3 , +.Xr posix_spawnattr_getflags 3 , +.Xr posix_spawnattr_getpgroup 3 , +.Xr posix_spawnattr_getschedparam 3 , +.Xr posix_spawnattr_getschedpolicy 3 , +.Xr posix_spawnattr_getsigdefault 3 , +.Xr posix_spawnattr_getsigmask 3 , +.Xr posix_spawnattr_init 3 , +.Xr posix_spawnattr_setflags 3 , +.Xr posix_spawnattr_setpgroup 3 , +.Xr posix_spawnattr_setschedparam 3 , +.Xr posix_spawnattr_setschedpolicy 3 , +.Xr posix_spawnattr_setsigdefault 3 , +.Xr posix_spawnattr_setsigmask 3 +.Sh STANDARDS +The +.Fn posix_spawn +and +.Fn posix_spawnp +functions conform to +.St -p1003.1-2001 , +except that they ignore all errors from +.Fn close . +A future update of the Standard is expected to require that these functions +not fail because a file descriptor to be closed (via +.Fn posix_spawn_file_actions_addclose ) +is not open. +.Sh HISTORY +The +.Fn posix_spawn +and +.Fn posix_spawnp +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawn.c b/lib/libc/gen/posix_spawn.c new file mode 100644 index 000000000000..a5b732696b8c --- /dev/null +++ b/lib/libc/gen/posix_spawn.c @@ -0,0 +1,690 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/procctl.h> +#include <sys/queue.h> +#include <sys/wait.h> + +#include <errno.h> +#include <fcntl.h> +#include <sched.h> +#include <spawn.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" +#include "libc_private.h" + +struct __posix_spawnattr { + short sa_flags; + pid_t sa_pgroup; + struct sched_param sa_schedparam; + int sa_schedpolicy; + sigset_t sa_sigdefault; + sigset_t sa_sigmask; +}; + +struct __posix_spawn_file_actions { + STAILQ_HEAD(, __posix_spawn_file_actions_entry) fa_list; +}; + +typedef struct __posix_spawn_file_actions_entry { + STAILQ_ENTRY(__posix_spawn_file_actions_entry) fae_list; + enum { + FAE_OPEN, + FAE_DUP2, + FAE_CLOSE, + FAE_CHDIR, + FAE_FCHDIR, + FAE_CLOSEFROM, + } fae_action; + + int fae_fildes; + union { + struct { + char *path; +#define fae_path fae_data.open.path + int oflag; +#define fae_oflag fae_data.open.oflag + mode_t mode; +#define fae_mode fae_data.open.mode + } open; + struct { + int newfildes; +#define fae_newfildes fae_data.dup2.newfildes + } dup2; + } fae_data; +} posix_spawn_file_actions_entry_t; + +/* + * Spawn routines + */ + +static int +process_spawnattr(const posix_spawnattr_t sa) +{ + struct sigaction sigact = { .sa_flags = 0, .sa_handler = SIG_DFL }; + int aslr, i; + + /* + * POSIX doesn't really describe in which order everything + * should be set. We'll just set them in the order in which they + * are mentioned. + */ + + /* Set process group */ + if (sa->sa_flags & POSIX_SPAWN_SETPGROUP) { + if (setpgid(0, sa->sa_pgroup) != 0) + return (errno); + } + + /* Set scheduler policy */ + if (sa->sa_flags & POSIX_SPAWN_SETSCHEDULER) { + if (sched_setscheduler(0, sa->sa_schedpolicy, + &sa->sa_schedparam) != 0) + return (errno); + } else if (sa->sa_flags & POSIX_SPAWN_SETSCHEDPARAM) { + if (sched_setparam(0, &sa->sa_schedparam) != 0) + return (errno); + } + + /* Reset user ID's */ + if (sa->sa_flags & POSIX_SPAWN_RESETIDS) { + if (setegid(getgid()) != 0) + return (errno); + if (seteuid(getuid()) != 0) + return (errno); + } + + /* + * Set signal masks/defaults. + * Use unwrapped syscall, libthr is in undefined state after vfork(). + */ + if (sa->sa_flags & POSIX_SPAWN_SETSIGMASK) { + __sys_sigprocmask(SIG_SETMASK, &sa->sa_sigmask, NULL); + } + + if (sa->sa_flags & POSIX_SPAWN_SETSIGDEF) { + for (i = 1; i <= _SIG_MAXSIG; i++) { + if (sigismember(&sa->sa_sigdefault, i)) + if (__sys_sigaction(i, &sigact, NULL) != 0) + return (errno); + } + } + + /* Disable ASLR. */ + if ((sa->sa_flags & POSIX_SPAWN_DISABLE_ASLR_NP) != 0) { + aslr = PROC_ASLR_FORCE_DISABLE; + if (procctl(P_PID, 0, PROC_ASLR_CTL, &aslr) != 0) + return (errno); + } + + return (0); +} + +static int +process_file_actions_entry(posix_spawn_file_actions_entry_t *fae) +{ + int fd, saved_errno; + + switch (fae->fae_action) { + case FAE_OPEN: + /* Perform an open(), make it use the right fd */ + fd = _open(fae->fae_path, fae->fae_oflag, fae->fae_mode); + if (fd < 0) + return (errno); + if (fd != fae->fae_fildes) { + if (_dup2(fd, fae->fae_fildes) == -1) { + saved_errno = errno; + (void)_close(fd); + return (saved_errno); + } + if (_close(fd) != 0) { + if (errno == EBADF) + return (EBADF); + } + } + if (_fcntl(fae->fae_fildes, F_SETFD, 0) == -1) + return (errno); + break; + case FAE_DUP2: + /* Perform a dup2() */ + if (_dup2(fae->fae_fildes, fae->fae_newfildes) == -1) + return (errno); + if (_fcntl(fae->fae_newfildes, F_SETFD, 0) == -1) + return (errno); + break; + case FAE_CLOSE: + /* Perform a close(), do not fail if already closed */ + (void)_close(fae->fae_fildes); + break; + case FAE_CHDIR: + if (chdir(fae->fae_path) != 0) + return (errno); + break; + case FAE_FCHDIR: + if (fchdir(fae->fae_fildes) != 0) + return (errno); + break; + case FAE_CLOSEFROM: + closefrom(fae->fae_fildes); + break; + } + return (0); +} + +static int +process_file_actions(const posix_spawn_file_actions_t fa) +{ + posix_spawn_file_actions_entry_t *fae; + int error; + + /* Replay all file descriptor modifications */ + STAILQ_FOREACH(fae, &fa->fa_list, fae_list) { + error = process_file_actions_entry(fae); + if (error) + return (error); + } + return (0); +} + +struct posix_spawn_args { + const char *path; + const posix_spawn_file_actions_t *fa; + const posix_spawnattr_t *sa; + char * const * argv; + char * const * envp; + int use_env_path; + volatile int error; +}; + +#define PSPAWN_STACK_ALIGNMENT 16 +#define PSPAWN_STACK_ALIGNBYTES (PSPAWN_STACK_ALIGNMENT - 1) +#define PSPAWN_STACK_ALIGN(sz) \ + (((sz) + PSPAWN_STACK_ALIGNBYTES) & ~PSPAWN_STACK_ALIGNBYTES) + +#if defined(__i386__) || defined(__amd64__) +/* + * Below we'll assume that _RFORK_THREAD_STACK_SIZE is appropriately aligned for + * the posix_spawn() case where we do not end up calling execvpe and won't ever + * try to allocate space on the stack for argv[]. + */ +#define _RFORK_THREAD_STACK_SIZE 4096 +_Static_assert((_RFORK_THREAD_STACK_SIZE % PSPAWN_STACK_ALIGNMENT) == 0, + "Inappropriate stack size alignment"); +#endif + +static int +_posix_spawn_thr(void *data) +{ + struct posix_spawn_args *psa; + char * const *envp; + + psa = data; + if (psa->sa != NULL) { + psa->error = process_spawnattr(*psa->sa); + if (psa->error) + _exit(127); + } + if (psa->fa != NULL) { + psa->error = process_file_actions(*psa->fa); + if (psa->error) + _exit(127); + } + envp = psa->envp != NULL ? psa->envp : environ; + if (psa->use_env_path) + __libc_execvpe(psa->path, psa->argv, envp); + else + _execve(psa->path, psa->argv, envp); + psa->error = errno; + + /* This is called in such a way that it must not exit. */ + _exit(127); +} + +static int +do_posix_spawn(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *sa, + char * const argv[], char * const envp[], int use_env_path) +{ + struct posix_spawn_args psa; + pid_t p; +#ifdef _RFORK_THREAD_STACK_SIZE + char *stack; + size_t cnt, stacksz; + + stacksz = _RFORK_THREAD_STACK_SIZE; + if (use_env_path) { + /* + * We need to make sure we have enough room on the stack for the + * potential alloca() in execvPe if it gets kicked back an + * ENOEXEC from execve(2), plus the original buffer we gave + * ourselves; this protects us in the event that the caller + * intentionally or inadvertently supplies enough arguments to + * make us blow past the stack we've allocated from it. + */ + for (cnt = 0; argv[cnt] != NULL; ++cnt) + ; + stacksz += MAX(3, cnt + 2) * sizeof(char *); + stacksz = PSPAWN_STACK_ALIGN(stacksz); + } + + /* + * aligned_alloc is not safe to use here, because we can't guarantee + * that aligned_alloc and free will be provided by the same + * implementation. We've actively hit at least one application that + * will provide its own malloc/free but not aligned_alloc leading to + * a free by the wrong allocator. + */ + stack = malloc(stacksz); + if (stack == NULL) + return (ENOMEM); + stacksz = (((uintptr_t)stack + stacksz) & ~PSPAWN_STACK_ALIGNBYTES) - + (uintptr_t)stack; +#endif + psa.path = path; + psa.fa = fa; + psa.sa = sa; + psa.argv = argv; + psa.envp = envp; + psa.use_env_path = use_env_path; + psa.error = 0; + + /* + * Passing RFSPAWN to rfork(2) gives us effectively a vfork that drops + * non-ignored signal handlers. We'll fall back to the slightly less + * ideal vfork(2) if we get an EINVAL from rfork -- this should only + * happen with newer libc on older kernel that doesn't accept + * RFSPAWN. + * + * Combination of vfork() (or its equivalent rfork() form) and + * a special property of the libthr rtld locks ensure that + * rtld is operational in the child. In particular, libthr + * rtld locks do not store owner' tid into the lock word. + */ +#ifdef _RFORK_THREAD_STACK_SIZE + /* + * x86 stores the return address on the stack, so rfork(2) cannot work + * as-is because the child would clobber the return address of the + * parent. Because of this, we must use rfork_thread instead while + * almost every other arch stores the return address in a register. + */ + p = rfork_thread(RFSPAWN, stack + stacksz, _posix_spawn_thr, &psa); + free(stack); +#else + p = rfork(RFSPAWN); + if (p == 0) + /* _posix_spawn_thr does not return */ + _posix_spawn_thr(&psa); +#endif + /* + * The above block should leave us in a state where we've either + * succeeded and we're ready to process the results, or we need to + * fallback to vfork() if the kernel didn't like RFSPAWN. + */ + + if (p == -1 && errno == EINVAL) { + p = vfork(); + if (p == 0) + /* _posix_spawn_thr does not return */ + _posix_spawn_thr(&psa); + } + if (p == -1) + return (errno); + if (psa.error != 0) + /* Failed; ready to reap */ + _waitpid(p, NULL, WNOHANG); + else if (pid != NULL) + /* exec succeeded */ + *pid = p; + return (psa.error); +} + +int +posix_spawn(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *sa, + char * const argv[], char * const envp[]) +{ + return (do_posix_spawn(pid, path, fa, sa, argv, envp, 0)); +} + +int +posix_spawnp(pid_t *pid, const char *path, + const posix_spawn_file_actions_t *fa, + const posix_spawnattr_t *sa, + char * const argv[], char * const envp[]) +{ + return (do_posix_spawn(pid, path, fa, sa, argv, envp, 1)); +} + +/* + * File descriptor actions + */ + +int +posix_spawn_file_actions_init(posix_spawn_file_actions_t *ret) +{ + posix_spawn_file_actions_t fa; + + fa = malloc(sizeof(struct __posix_spawn_file_actions)); + if (fa == NULL) + return (-1); + + STAILQ_INIT(&fa->fa_list); + *ret = fa; + return (0); +} + +int +posix_spawn_file_actions_destroy(posix_spawn_file_actions_t *fa) +{ + posix_spawn_file_actions_entry_t *fae; + + while ((fae = STAILQ_FIRST(&(*fa)->fa_list)) != NULL) { + /* Remove file action entry from the queue */ + STAILQ_REMOVE_HEAD(&(*fa)->fa_list, fae_list); + + /* Deallocate file action entry */ + if (fae->fae_action == FAE_OPEN || + fae->fae_action == FAE_CHDIR) + free(fae->fae_path); + free(fae); + } + + free(*fa); + return (0); +} + +int +posix_spawn_file_actions_addopen(posix_spawn_file_actions_t * __restrict fa, + int fildes, const char * __restrict path, int oflag, mode_t mode) +{ + posix_spawn_file_actions_entry_t *fae; + int error; + + if (fildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + /* Set values and store in queue */ + fae->fae_action = FAE_OPEN; + fae->fae_path = strdup(path); + if (fae->fae_path == NULL) { + error = errno; + free(fae); + return (error); + } + fae->fae_fildes = fildes; + fae->fae_oflag = oflag; + fae->fae_mode = mode; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t *fa, + int fildes, int newfildes) +{ + posix_spawn_file_actions_entry_t *fae; + + if (fildes < 0 || newfildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + /* Set values and store in queue */ + fae->fae_action = FAE_DUP2; + fae->fae_fildes = fildes; + fae->fae_newfildes = newfildes; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +posix_spawn_file_actions_addclose(posix_spawn_file_actions_t *fa, + int fildes) +{ + posix_spawn_file_actions_entry_t *fae; + + if (fildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + /* Set values and store in queue */ + fae->fae_action = FAE_CLOSE; + fae->fae_fildes = fildes; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +posix_spawn_file_actions_addchdir_np(posix_spawn_file_actions_t * + __restrict fa, const char *__restrict path) +{ + posix_spawn_file_actions_entry_t *fae; + int error; + + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + fae->fae_action = FAE_CHDIR; + fae->fae_path = strdup(path); + if (fae->fae_path == NULL) { + error = errno; + free(fae); + return (error); + } + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +posix_spawn_file_actions_addfchdir_np(posix_spawn_file_actions_t *__restrict fa, + int fildes) +{ + posix_spawn_file_actions_entry_t *fae; + + if (fildes < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + fae->fae_action = FAE_FCHDIR; + fae->fae_fildes = fildes; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +int +posix_spawn_file_actions_addclosefrom_np (posix_spawn_file_actions_t * + __restrict fa, int from) +{ + posix_spawn_file_actions_entry_t *fae; + + if (from < 0) + return (EBADF); + + /* Allocate object */ + fae = malloc(sizeof(posix_spawn_file_actions_entry_t)); + if (fae == NULL) + return (errno); + + fae->fae_action = FAE_CLOSEFROM; + fae->fae_fildes = from; + + STAILQ_INSERT_TAIL(&(*fa)->fa_list, fae, fae_list); + return (0); +} + +/* + * Spawn attributes + */ + +int +posix_spawnattr_init(posix_spawnattr_t *ret) +{ + posix_spawnattr_t sa; + + sa = calloc(1, sizeof(struct __posix_spawnattr)); + if (sa == NULL) + return (errno); + + /* Set defaults as specified by POSIX, cleared above */ + *ret = sa; + return (0); +} + +int +posix_spawnattr_destroy(posix_spawnattr_t *sa) +{ + free(*sa); + return (0); +} + +int +posix_spawnattr_getflags(const posix_spawnattr_t * __restrict sa, + short * __restrict flags) +{ + *flags = (*sa)->sa_flags; + return (0); +} + +int +posix_spawnattr_getpgroup(const posix_spawnattr_t * __restrict sa, + pid_t * __restrict pgroup) +{ + *pgroup = (*sa)->sa_pgroup; + return (0); +} + +int +posix_spawnattr_getschedparam(const posix_spawnattr_t * __restrict sa, + struct sched_param * __restrict schedparam) +{ + *schedparam = (*sa)->sa_schedparam; + return (0); +} + +int +posix_spawnattr_getschedpolicy(const posix_spawnattr_t * __restrict sa, + int * __restrict schedpolicy) +{ + *schedpolicy = (*sa)->sa_schedpolicy; + return (0); +} + +int +posix_spawnattr_getsigdefault(const posix_spawnattr_t * __restrict sa, + sigset_t * __restrict sigdefault) +{ + *sigdefault = (*sa)->sa_sigdefault; + return (0); +} + +int +posix_spawnattr_getsigmask(const posix_spawnattr_t * __restrict sa, + sigset_t * __restrict sigmask) +{ + *sigmask = (*sa)->sa_sigmask; + return (0); +} + +int +posix_spawnattr_setflags(posix_spawnattr_t *sa, short flags) +{ + if ((flags & ~(POSIX_SPAWN_RESETIDS | POSIX_SPAWN_SETPGROUP | + POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER | + POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK | + POSIX_SPAWN_DISABLE_ASLR_NP)) != 0) + return (EINVAL); + (*sa)->sa_flags = flags; + return (0); +} + +int +posix_spawnattr_setpgroup(posix_spawnattr_t *sa, pid_t pgroup) +{ + (*sa)->sa_pgroup = pgroup; + return (0); +} + +int +posix_spawnattr_setschedparam(posix_spawnattr_t * __restrict sa, + const struct sched_param * __restrict schedparam) +{ + (*sa)->sa_schedparam = *schedparam; + return (0); +} + +int +posix_spawnattr_setschedpolicy(posix_spawnattr_t *sa, int schedpolicy) +{ + (*sa)->sa_schedpolicy = schedpolicy; + return (0); +} + +int +posix_spawnattr_setsigdefault(posix_spawnattr_t * __restrict sa, + const sigset_t * __restrict sigdefault) +{ + (*sa)->sa_sigdefault = *sigdefault; + return (0); +} + +int +posix_spawnattr_setsigmask(posix_spawnattr_t * __restrict sa, + const sigset_t * __restrict sigmask) +{ + (*sa)->sa_sigmask = *sigmask; + return (0); +} diff --git a/lib/libc/gen/posix_spawn_file_actions_addopen.3 b/lib/libc/gen/posix_spawn_file_actions_addopen.3 new file mode 100644 index 000000000000..80bc91454471 --- /dev/null +++ b/lib/libc/gen/posix_spawn_file_actions_addopen.3 @@ -0,0 +1,275 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd May 9, 2013 +.Dt POSIX_SPAWN_FILE_ACTIONS_ADDOPEN 3 +.Os +.Sh NAME +.Nm posix_spawn_file_actions_addopen , +.Nm posix_spawn_file_actions_adddup2 , +.Nm posix_spawn_file_actions_addclose , +.Nm posix_spawn_file_actions_addclosefrom_np , +.Nm posix_spawn_file_actions_addchdir_np , +.Nm posix_spawn_file_actions_addfchdir_np +.Nd "add open, dup2, close, closefrom, or chdir/fchdir actions to spawn file actions object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fo posix_spawn_file_actions_addopen +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fa "const char *restrict path" +.Fa "int oflag" +.Fa "mode_t mode" +.Fc +.Ft int +.Fo posix_spawn_file_actions_adddup2 +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fa "int newfildes" +.Fc +.Ft int +.Fo posix_spawn_file_actions_addclose +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fc +.Ft int +.Fo posix_spawn_file_actions_addclosefrom_np +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int from" +.Fc +.Ft int +.Fo posix_spawn_file_actions_addchdir_np +.Fa "posix_spawn_file_actions_t *restrict file_actions" +.Fa "const char *restrict path" +.Fc +.Ft int +.Fo posix_spawn_file_actions_addfchdir_np +.Fa "posix_spawn_file_actions_t * file_actions" +.Fa "int fildes" +.Fc +.Sh DESCRIPTION +These functions add an open, dup2 or close action to a spawn +file actions object. +.Pp +A spawn file actions object is of type +.Vt posix_spawn_file_actions_t +(defined in +.In spawn.h ) +and is used to specify a series of actions to be performed by a +.Fn posix_spawn +or +.Fn posix_spawnp +operation in order to arrive at the set of open file descriptors for the +child process given the set of open file descriptors of the parent. +.Pp +A spawn file actions object, when passed to +.Fn posix_spawn +or +.Fn posix_spawnp , +specify how the set of open file descriptors in the calling +process is transformed into a set of potentially open file descriptors +for the spawned process. +This transformation is as if the specified sequence of actions was +performed exactly once, in the context of the spawned process (prior to +execution of the new process image), in the order in which the actions +were added to the object; additionally, when the new process image is +executed, any file descriptor (from this new set) which has its +.Dv FD_CLOEXEC +flag set is closed (see +.Fn posix_spawn ) . +.Pp +The +.Fn posix_spawn_file_actions_addopen +function adds an open action to the object referenced by +.Fa file_actions +that causes the file named by +.Fa path +to be opened (as if +.Bd -literal -offset indent +open(path, oflag, mode) +.Ed +.Pp +had been called, and the returned file descriptor, if not +.Fa fildes , +had been changed to +.Fa fildes ) +when a new process is spawned using this file actions object. +If +.Fa fildes +was already an open file descriptor, it is closed before the new +file is opened. +.Pp +The string described by +.Fa path +is copied by the +.Fn posix_spawn_file_actions_addopen +function. +.Pp +The +.Fn posix_spawn_file_actions_adddup2 +function adds a dup2 action to the object referenced by +.Fa file_actions +that causes the file descriptor +.Fa fildes +to be duplicated as +.Fa newfildes +(as if +.Bd -literal -offset indent +dup2(fildes, newfildes) +.Ed +.Pp +had been called) when a new process is spawned using this file actions object, +except that the +.Dv FD_CLOEXEC +flag for +.Fa newfildes +is cleared even if +.Fa fildes +is equal to +.Fa newfildes . +The difference from +.Fn dup2 +is useful for passing a particular file descriptor +to a particular child process. +.Pp +The +.Fn posix_spawn_file_actions_addclose +function adds a close action to the object referenced by +.Fa file_actions +that causes the file descriptor +.Fa fildes +to be closed (as if +.Bd -literal -offset indent +close(fildes) +.Ed +.Pp +had been called) when a new process is spawned using this file actions +object. +.Pp +The +.Fn posix_spawn_file_actions_addclosefrom_np +function adds a close action to close all file descriptors numerically +equal or greater then the argument +.Fa from . +For each open file descriptor, logically the close action is performed, +and any possible errors encountered are ignored. +.Pp +The +.Fn posix_spawn_file_actions_addchdir_np +and +.Fn posix_spawn_file_actions_addfchdir_np +functions add a change current directory action to the object +referenced by +.Fa file_actions +that affects actions (opens with relative path) performed after the operation, +in the order of insertion into the +.Fa file_actions +object. +It also sets the working directory for the spawned program. +The +.Fn posix_spawn_file_actions_addchdir_np +function takes the +.Fa path +to set as the working directory, while +.Fn posix_spawn_file_actions_addfchdir_np +takes the directory file descriptor. +.Sh RETURN VALUES +Upon successful completion, these functions return zero; +otherwise, an error number is returned to indicate the error. +.Sh ERRORS +These +functions fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The value specified by +.Fa fildes +or +.Fa newfildes +is negative. +.It Bq Er ENOMEM +Insufficient memory exists to add to the spawn file actions object. +.El +.Sh SEE ALSO +.Xr close 2 , +.Xr dup2 2 , +.Xr open 2 , +.Xr posix_spawn 3 , +.Xr posix_spawn_file_actions_destroy 3 , +.Xr posix_spawn_file_actions_init 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawn_file_actions_addopen , +.Fn posix_spawn_file_actions_adddup2 +and +.Fn posix_spawn_file_actions_addclose +functions conform to +.St -p1003.1-2001 , +with the exception of the behavior of +.Fn posix_spawn_file_actions_adddup2 +if +.Fa fildes +is equal to +.Fa newfildes +(clearing +.Dv FD_CLOEXEC ) . +A future update of the Standard is expected to require this behavior. +.Pp +The +.Fn posix_spawn_file_actions_addchdir_np , +.Fn posix_spawn_file_actions_addfchdir_np , +and +.Fn posix_spawn_file_actions_addclosefrom_np +functions are non-standard functions implemented after the similar +functionality provided by glibc. +.Sh HISTORY +The +.Fn posix_spawn_file_actions_addopen , +.Fn posix_spawn_file_actions_adddup2 +and +.Fn posix_spawn_file_actions_addclose +functions first appeared in +.Fx 8.0 . +The +.Fn posix_spawn_file_actions_addchdir_np , +.Fn posix_spawn_file_actions_addfchdir_np , +and +.Fn posix_spawn_file_actions_addclosefrom_np +functions first appeared in +.Fx 13.1 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawn_file_actions_init.3 b/lib/libc/gen/posix_spawn_file_actions_init.3 new file mode 100644 index 000000000000..43b176441381 --- /dev/null +++ b/lib/libc/gen/posix_spawn_file_actions_init.3 @@ -0,0 +1,103 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd November 28, 2021 +.Dt POSIX_SPAWN_FILE_ACTIONS_INIT 3 +.Os +.Sh NAME +.Nm posix_spawn_file_actions_init , +.Nm posix_spawn_file_actions_destroy +.Nd "initialize and destroy spawn file actions object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawn_file_actions_init "posix_spawn_file_actions_t * file_actions" +.Ft int +.Fn posix_spawn_file_actions_destroy "posix_spawn_file_actions_t * file_actions" +.Sh DESCRIPTION +The +.Fn posix_spawn_file_actions_init +function initialize the object referenced by +.Fn file_actions +to contain no file actions for +.Fn posix_spawn +or +.Fn posix_spawnp . +Initializing an already initialized spawn file actions object may cause +memory to be leaked. +.Pp +The +.Fn posix_spawn_file_actions_destroy +function destroy the object referenced by +.Fa file_actions ; +the object becomes, in effect, uninitialized. +A destroyed spawn file actions object can be reinitialized using +.Fn posix_spawn_file_actions_init . +The object should not be used after it has been destroyed. +.Sh RETURN VALUES +Upon successful completion, these functions return zero; +otherwise, an error number is returned to indicate the error. +.Sh ERRORS +The +.Fn posix_spawn_file_actions_init +function will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Insufficient memory exists to initialize the spawn file actions object. +.El +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawn_file_actions_addclose 3 , +.Xr posix_spawn_file_actions_addclosefrom_np 3 , +.Xr posix_spawn_file_actions_adddup2 3 , +.Xr posix_spawn_file_actions_addopen 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawn_file_actions_init +and +.Fn posix_spawn_file_actions_destroy +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawn_file_actions_init +and +.Fn posix_spawn_file_actions_destroy +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawnattr_getflags.3 b/lib/libc/gen/posix_spawnattr_getflags.3 new file mode 100644 index 000000000000..308bbb386d76 --- /dev/null +++ b/lib/libc/gen/posix_spawnattr_getflags.3 @@ -0,0 +1,113 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 4, 2024 +.Dt POSIX_SPAWNATTR_GETFLAGS 3 +.Os +.Sh NAME +.Nm posix_spawnattr_getflags , +.Nm posix_spawnattr_setflags +.Nd "get and set the spawn-flags attribute of a spawn attributes object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawnattr_getflags "const posix_spawnattr_t *restrict attr" "short *restrict flags" +.Ft int +.Fn posix_spawnattr_setflags "posix_spawnattr_t *attr" "short flags" +.Sh DESCRIPTION +The +.Fn posix_spawnattr_getflags +function obtains the value of the spawn-flags attribute from the +attributes object referenced by +.Fa attr . +.Pp +The +.Fn posix_spawnattr_setflags +function sets the spawn-flags attribute in an initialized +attributes object referenced by +.Fa attr . +.Pp +The spawn-flags attribute is used to indicate which process attributes +are to be changed in the new process image when invoking +.Fn posix_spawn +or +.Fn posix_spawnp . +It is the bitwise-inclusive OR of zero or more of the following flags +(see +.Fn posix_spawn ) : +.Bl -tag -width "POSIX_SPAWN_SETSCHEDPARAM" -offset indent +.It Dv POSIX_SPAWN_RESETIDS +.It Dv POSIX_SPAWN_SETPGROUP +.It Dv POSIX_SPAWN_SETSIGDEF +.It Dv POSIX_SPAWN_SETSIGMASK +.It Dv POSIX_SPAWN_SETSCHEDPARAM +.It Dv POSIX_SPAWN_SETSCHEDULER +.It Dv POSIX_SPAWN_DISABLE_ASLR_NP +.El +.Pp +These flags are defined in +.In spawn.h . +The default value of this attribute is as if no flags were set. +.Sh RETURN VALUES +The +.Fn posix_spawnattr_getflags +function returns zero. +The +.Fn posix_spawnattr_setflags +function returns zero on success, and +.Er EINVAL +on failure due to invalid flag specified. +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawnattr_destroy 3 , +.Xr posix_spawnattr_init 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawnattr_getflags +and +.Fn posix_spawnattr_setflags +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawnattr_getflags +and +.Fn posix_spawnattr_setflags +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawnattr_getpgroup.3 b/lib/libc/gen/posix_spawnattr_getpgroup.3 new file mode 100644 index 000000000000..cd8cb4899fa3 --- /dev/null +++ b/lib/libc/gen/posix_spawnattr_getpgroup.3 @@ -0,0 +1,94 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 24, 2008 +.Dt POSIX_SPAWNATTR_GETPGROUP 3 +.Os +.Sh NAME +.Nm posix_spawnattr_getpgroup , +.Nm posix_spawnattr_setpgroup +.Nd "get and set the spawn-pgroup attribute of a spawn attributes object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawnattr_getpgroup "const posix_spawnattr_t *restrict attr" "pid_t *restrict pgroup" +.Ft int +.Fn posix_spawnattr_setpgroup "posix_spawnattr_t *attr" "pid_t pgroup" +.Sh DESCRIPTION +The +.Fn posix_spawnattr_getpgroup +function obtains the value of the spawn-pgroup attribute from the +attributes object referenced by +.Fa attr . +.Pp +The +.Fn posix_spawnattr_setpgroup +function sets the spawn-pgroup attribute in an initialized +attributes object referenced by +.Fa attr . +.Pp +The spawn-pgroup attribute represents the process group to be joined by +the new process image in a spawn operation (if +.Dv POSIX_SPAWN_SETPGROUP +is set in the spawn-flags attribute). +The default value of this attribute is zero. +.Sh RETURN VALUES +The +.Fn posix_spawnattr_getpgroup +and +.Fn posix_spawnattr_setpgroup +functions return zero. +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawnattr_destroy 3 , +.Xr posix_spawnattr_init 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawnattr_getpgroup +and +.Fn posix_spawnattr_setpgroup +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawnattr_getpgroup +and +.Fn posix_spawnattr_setpgroup +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawnattr_getschedparam.3 b/lib/libc/gen/posix_spawnattr_getschedparam.3 new file mode 100644 index 000000000000..bdb560d954e6 --- /dev/null +++ b/lib/libc/gen/posix_spawnattr_getschedparam.3 @@ -0,0 +1,98 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 24, 2008 +.Dt POSIX_SPAWNATTR_GETSCHEDPARAM 3 +.Os +.Sh NAME +.Nm posix_spawnattr_getschedparam , +.Nm posix_spawnattr_setschedparam +.Nd "get and set the spawn-schedparam attribute of a spawn attributes object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawnattr_getschedparam "const posix_spawnattr_t *restrict attr" "struct sched_param *restrict schedparam" +.Ft int +.Fn posix_spawnattr_setschedparam "posix_spawnattr_t *attr" "const struct sched_param *restrict schedparam" +.Sh DESCRIPTION +The +.Fn posix_spawnattr_getschedparam +function obtains the value of the spawn-schedparam attribute from the +attributes object referenced by +.Fa attr . +.Pp +The +.Fn posix_spawnattr_setschedparam +function sets the spawn-schedparam attribute in an initialized attributes +object referenced by +.Fa attr . +.Pp +The spawn-schedparam attribute represents the scheduling parameters to +be assigned to the new process image in a spawn operation (if +.Dv POSIX_SPAWN_SETSCHEDULER +or +.Dv POSIX_SPAWN_SETSCHEDPARAM +is set in the spawn-flags attribute). +The default value of this attribute is unspecified. +.Sh RETURN VALUES +The +.Fn posix_spawnattr_getschedparam +and +.Fn posix_spawnattr_setschedparam +functions return zero. +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawnattr_destroy 3 , +.Xr posix_spawnattr_getschedpolicy 3 , +.Xr posix_spawnattr_init 3 , +.Xr posix_spawnattr_setschedpolicy 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawnattr_getschedparam +and +.Fn posix_spawnattr_setschedparam +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawnattr_getschedparam +and +.Fn posix_spawnattr_setschedparam +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawnattr_getschedpolicy.3 b/lib/libc/gen/posix_spawnattr_getschedpolicy.3 new file mode 100644 index 000000000000..f6d32babd29b --- /dev/null +++ b/lib/libc/gen/posix_spawnattr_getschedpolicy.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 24, 2008 +.Dt POSIX_SPAWNATTR_GETSCHEDPOLICY 3 +.Os +.Sh NAME +.Nm posix_spawnattr_getschedpolicy , +.Nm posix_spawnattr_setschedpolicy +.Nd "get and set the spawn-schedpolicy attribute of a spawn attributes object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawnattr_getschedpolicy "const posix_spawnattr_t *restrict attr" "int *restrict schedpolicy" +.Ft int +.Fn posix_spawnattr_setschedpolicy "posix_spawnattr_t *attr" "int schedpolicy" +.Sh DESCRIPTION +The +.Fn posix_spawnattr_getschedpolicy +function obtains the value of the spawn-schedpolicy attribute from the +attributes object referenced by +.Fa attr . +.Pp +The +.Fn posix_spawnattr_setschedpolicy +function sets the spawn-schedpolicy attribute in an initialized attributes +object referenced by +.Fa attr . +.Pp +The spawn-schedpolicy attribute represents the scheduling policy to +be assigned to the new process image in a spawn operation (if +.Dv POSIX_SPAWN_SETSCHEDULER +is set in the spawn-flags attribute). +The default value of this attribute is unspecified. +.Sh RETURN VALUES +The +.Fn posix_spawnattr_getschedpolicy +and +.Fn posix_spawnattr_setschedpolicy +functions return zero. +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawnattr_destroy 3 , +.Xr posix_spawnattr_getschedparam 3 , +.Xr posix_spawnattr_init 3 , +.Xr posix_spawnattr_setschedparam 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawnattr_getschedpolicy +and +.Fn posix_spawnattr_setschedpolicy +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawnattr_getschedpolicy +and +.Fn posix_spawnattr_setschedpolicy +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawnattr_getsigdefault.3 b/lib/libc/gen/posix_spawnattr_getsigdefault.3 new file mode 100644 index 000000000000..897c337badfe --- /dev/null +++ b/lib/libc/gen/posix_spawnattr_getsigdefault.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 24, 2008 +.Dt POSIX_SPAWNATTR_GETSIGDEFAULT 3 +.Os +.Sh NAME +.Nm posix_spawnattr_getsigdefault , +.Nm posix_spawnattr_setsigdefault +.Nd "get and set the spawn-sigdefault attribute of a spawn attributes object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawnattr_getsigdefault "const posix_spawnattr_t *restrict attr" "sigset_t *restrict sigdefault" +.Ft int +.Fn posix_spawnattr_setsigdefault "posix_spawnattr_t *attr" "const sigset_t *restrict sigdefault" +.Sh DESCRIPTION +The +.Fn posix_spawnattr_getsigdefault +function obtains the value of the spawn-sigdefault attribute from the +attributes object referenced by +.Fa attr . +.Pp +The +.Fn posix_spawnattr_setsigdefault +function sets the spawn-sigdefault attribute in an initialized attributes +object referenced by +.Fa attr . +.Pp +The spawn-sigdefault attribute represents the set of signals to be forced to +default signal handling in the new process image (if +.Dv POSIX_SPAWN_SETSIGDEF +is set in the spawn-flags attribute) by a spawn operation. +The default value of this attribute is an empty signal set. +.Sh RETURN VALUES +The +.Fn posix_spawnattr_getsigdefault +and +.Fn posix_spawnattr_setsigdefault +functions return zero. +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawnattr_destroy 3 , +.Xr posix_spawnattr_getsigmask 3 , +.Xr posix_spawnattr_init 3 , +.Xr posix_spawnattr_setsigmask 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawnattr_getsigdefault +and +.Fn posix_spawnattr_setsigdefault +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawnattr_getsigdefault +and +.Fn posix_spawnattr_setsigdefault +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawnattr_getsigmask.3 b/lib/libc/gen/posix_spawnattr_getsigmask.3 new file mode 100644 index 000000000000..3800a9bc4325 --- /dev/null +++ b/lib/libc/gen/posix_spawnattr_getsigmask.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 24, 2008 +.Dt POSIX_SPAWNATTR_GETSIGMASK 3 +.Os +.Sh NAME +.Nm posix_spawnattr_getsigmask , +.Nm posix_spawnattr_setsigmask +.Nd "get and set the spawn-sigmask attribute of a spawn attributes object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawnattr_getsigmask "const posix_spawnattr_t *restrict attr" "sigset_t *restrict sigmask" +.Ft int +.Fn posix_spawnattr_setsigmask "posix_spawnattr_t *attr" "const sigset_t *restrict sigmask" +.Sh DESCRIPTION +The +.Fn posix_spawnattr_getsigmask +function obtains the value of the spawn-sigmask attribute from the +attributes object referenced by +.Fa attr . +.Pp +The +.Fn posix_spawnattr_setsigmask +function sets the spawn-sigmask attribute in an initialized attributes +object referenced by +.Fa attr . +.Pp +The spawn-sigmask attribute represents the signal mask in effect in the +new process image of a spawn operation (if +.Dv POSIX_SPAWN_SETSIGMASK +is set in the spawn-flags attribute). +The default value of this attribute is unspecified. +.Sh RETURN VALUES +The +.Fn posix_spawnattr_getsigmask +and +.Fn posix_spawnattr_setsigmask +functions return zero. +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawnattr_destroy 3 , +.Xr posix_spawnattr_getsigmask 3 , +.Xr posix_spawnattr_init 3 , +.Xr posix_spawnattr_setsigmask 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawnattr_getsigmask +and +.Fn posix_spawnattr_setsigmask +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawnattr_getsigmask +and +.Fn posix_spawnattr_setsigmask +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/posix_spawnattr_init.3 b/lib/libc/gen/posix_spawnattr_init.3 new file mode 100644 index 000000000000..e5b921967bf0 --- /dev/null +++ b/lib/libc/gen/posix_spawnattr_init.3 @@ -0,0 +1,121 @@ +.\" Copyright (c) 2008 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd March 24, 2008 +.Dt POSIX_SPAWNATTR_INIT 3 +.Os +.Sh NAME +.Nm posix_spawnattr_init , +.Nm posix_spawnattr_destroy +.Nd "initialize and destroy spawn attributes object" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In spawn.h +.Ft int +.Fn posix_spawnattr_init "posix_spawnattr_t * attr" +.Ft int +.Fn posix_spawnattr_destroy "posix_spawnattr_t * attr" +.Sh DESCRIPTION +The +.Fn posix_spawnattr_init +function initializes a spawn attributes object +.Fa attr +with the default value for all of the individual attributes used by the +implementation. +Initializing an already initialized spawn attributes object may cause +memory to be leaked. +.Pp +The +.Fn posix_spawnattr_destroy +function destroys a spawn attributes object. +A destroyed +.Fa attr +attributes object can be reinitialized using +.Fn posix_spawnattr_init . +The object should not be used after it has been destroyed. +.Pp +A spawn attributes object is of type +.Vt posix_spawnattr_t +(defined in +.In spawn.h ) +and is used to specify the inheritance of process attributes across a +spawn operation. +.Pp +The resulting spawn attributes object (possibly modified by setting +individual attribute values), is used to modify the behavior of +.Fn posix_spawn +or +.Fn posix_spawnp . +After a spawn attributes object has been used to spawn a process by a +call to a +.Fn posix_spawn +or +.Fn posix_spawnp , +any function affecting the attributes object (including destruction) +will not affect any process that has been spawned in this way. +.Sh RETURN VALUES +Upon successful completion, +.Fn posix_spawnattr_init +and +.Fn posix_spawnattr_destroy +return zero; +otherwise, an error number is returned to indicate the error. +.Sh ERRORS +The +.Fn posix_spawnattr_init +function will fail if: +.Bl -tag -width Er +.It Bq Er ENOMEM +Insufficient memory exists to initialize the spawn attributes object. +.El +.Sh SEE ALSO +.Xr posix_spawn 3 , +.Xr posix_spawnp 3 +.Sh STANDARDS +The +.Fn posix_spawnattr_init +and +.Fn posix_spawnattr_destroy +functions conform to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn posix_spawnattr_init +and +.Fn posix_spawnattr_destroy +functions first appeared in +.Fx 8.0 . +.Sh AUTHORS +.An \&Ed Schouten Aq Mt ed@FreeBSD.org diff --git a/lib/libc/gen/psignal.3 b/lib/libc/gen/psignal.3 new file mode 100644 index 000000000000..bf6a99b4b113 --- /dev/null +++ b/lib/libc/gen/psignal.3 @@ -0,0 +1,185 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd September 23, 2025 +.Dt PSIGNAL 3 +.Os +.Sh NAME +.Nm psignal , +.Nm psiginfo , +.Nm strsignal , +.Nm sys_siglist , +.Nm sys_signame , +.Nm sig2str , +.Nm str2sig +.Nd system signal messages +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In signal.h +.Ft void +.Fn psignal "int sig" "const char *s" +.Ft void +.Fn psiginfo "const siginfo_t *si" "const char *s" +.Vt extern const char * const sys_siglist[] ; +.Vt extern const char * const sys_signame[] ; +.In string.h +.Ft "char *" +.Fn strsignal "int sig" +.Ft int +.Fn sig2str "int signum" "char *str" +.Ft int +.Fn str2sig "char *str" "int *pnum" +.Sh DESCRIPTION +The +.Fn psignal +and +.Fn strsignal +functions locate the descriptive message +string for a signal number. +.Pp +The +.Fn strsignal +function accepts a signal number argument +.Fa sig +and returns a pointer to the corresponding message string. +.Pp +The +.Fn psignal +function accepts a signal number argument +.Fa sig +and writes it to the standard error. +If the argument +.Fa s +is +.Pf non- Dv NULL +and does not point to the null character, +.Fa s +is written to the standard error file descriptor +prior to the message string, +immediately followed by a colon and a space. +If the signal number is not recognized +.Pq Xr sigaction 2 , +the string +.Dq "Unknown signal" +is produced. +.Pp +The +.Fn psiginfo +function is similar to +.Fn psignal , +except that the signal number information is taken from the +.Fa si +argument which is a +.Vt siginfo_t +structure. +.Pp +The message strings can be accessed directly +through the external array +.Va sys_siglist , +indexed by recognized signal numbers. +The external array +.Va sys_signame +is used similarly and +contains short, upper-case abbreviations for signals +which are useful for recognizing signal names +in user input. +The defined variable +.Dv NSIG +contains a count of the strings in +.Va sys_siglist +and +.Va sys_signame . +.Pp +The +.Fn sig2str +function translates the signal number +.Fa signum +to the signal name, without the +.Dq SIG +prefix, and stores it at the location specified by +.Fa str , +which should be large enough to hold the name and the terminating +.Dv NUL +byte. +The symbol +.Dv SIG2STR_MAX +gives the maximum size in bytes required. +.Pp +The +.Fn str2sig +function translates the signal name +.Fa str +to a signal number and stores it in the location referenced by +.Fa pnum . +The name in +.Fa str +can be either the name of the signal, with or without the +.Dq SIG +prefix, or a decimal number. +.Sh RETURN VALUES +The +.Fn sig2str +and +.Fn str2sig +return 0 on success and -1 on translation failure. +In the latter case the memory to store the translation result is left intact. +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr perror 3 , +.Xr strerror 3 +.Sh STANDARDS +The +.Fn psignal +and +.Fn psiginfo +functions are defined by +.St -p1003.1-2008 +, while the +.Fn sig2str +and +.Fn str2sig +functions are defined by +.St -p1003.1-2024 . +.Sh HISTORY +The +.Fn psignal +function appeared in +.Bx 4.2 . +The +.Fn psiginfo +function appeared in +.Fx 14.3 , +.Nx 6.0 , +and +.Dx 4.1 . +The +.Fn sig2str +and +.Fn str2sig +functions appeared in +.Fx 15.0 . diff --git a/lib/libc/gen/psignal.c b/lib/libc/gen/psignal.c new file mode 100644 index 000000000000..291a6a9337a0 --- /dev/null +++ b/lib/libc/gen/psignal.c @@ -0,0 +1,63 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Print the name of the signal indicated + * along with the supplied message. + */ +#include "namespace.h" +#include <signal.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +void +psignal(int sig, const char *s) +{ + const char *c; + + if (sig >= 0 && sig < NSIG) + c = sys_siglist[sig]; + else + c = "Unknown signal"; + if (s != NULL && *s != '\0') { + (void)_write(STDERR_FILENO, s, strlen(s)); + (void)_write(STDERR_FILENO, ": ", 2); + } + (void)_write(STDERR_FILENO, c, strlen(c)); + (void)_write(STDERR_FILENO, "\n", 1); +} + +void +psiginfo(const siginfo_t *si, const char *s) +{ + psignal(si->si_signo, s); +} diff --git a/lib/libc/gen/pututxline.c b/lib/libc/gen/pututxline.c new file mode 100644 index 000000000000..15df7b5f6783 --- /dev/null +++ b/lib/libc/gen/pututxline.c @@ -0,0 +1,334 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/endian.h> +#include <sys/stat.h> +#include <sys/uio.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <utmpx.h> +#include "utxdb.h" +#include "un-namespace.h" + +static FILE * +futx_open(const char *file) +{ + FILE *fp; + struct stat sb; + int fd; + + fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK|O_CLOEXEC, 0644); + if (fd < 0) + return (NULL); + + /* Safety check: never use broken files. */ + if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) { + _close(fd); + errno = EFTYPE; + return (NULL); + } + + fp = fdopen(fd, "r+"); + if (fp == NULL) { + _close(fd); + return (NULL); + } + return (fp); +} + +static int +utx_active_add(const struct futx *fu) +{ + FILE *fp; + struct futx fe; + off_t partial; + int error, ret; + + partial = -1; + ret = 0; + + /* + * Register user login sessions. Overwrite entries of sessions + * that have already been terminated. + */ + fp = futx_open(_PATH_UTX_ACTIVE); + if (fp == NULL) + return (-1); + while (fread(&fe, sizeof(fe), 1, fp) == 1) { + switch (fe.fu_type) { + case BOOT_TIME: + /* Leave these intact. */ + break; + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + case DEAD_PROCESS: + /* Overwrite when ut_id matches. */ + if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) == + 0) { + ret = fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR); + goto exact; + } + if (fe.fu_type != DEAD_PROCESS) + break; + /* FALLTHROUGH */ + default: + /* Allow us to overwrite unused records. */ + if (partial == -1) { + partial = ftello(fp); + /* + * Distinguish errors from valid values so we + * don't overwrite good data by accident. + */ + if (partial != -1) + partial -= (off_t)sizeof(fe); + } + break; + } + } + + /* + * No exact match found. Use the partial match. If no partial + * match was found, just append a new record. + */ + if (partial != -1) + ret = fseeko(fp, partial, SEEK_SET); +exact: + if (ret == -1) + error = errno; + else if (fwrite(fu, sizeof(*fu), 1, fp) < 1) + error = errno; + else + error = 0; + fclose(fp); + if (error != 0) + errno = error; + return (error == 0 ? 0 : 1); +} + +static int +utx_active_remove(struct futx *fu) +{ + FILE *fp; + struct futx fe; + int error, ret; + + /* + * Remove user login sessions, having the same ut_id. + */ + fp = futx_open(_PATH_UTX_ACTIVE); + if (fp == NULL) + return (-1); + error = ESRCH; + ret = -1; + while (fread(&fe, sizeof(fe), 1, fp) == 1 && ret != 0) + switch (fe.fu_type) { + case USER_PROCESS: + case INIT_PROCESS: + case LOGIN_PROCESS: + if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) != 0) + continue; + + /* Terminate session. */ + if (fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR) == -1) + error = errno; + else if (fwrite(fu, sizeof(*fu), 1, fp) < 1) + error = errno; + else + ret = 0; + + } + + fclose(fp); + if (ret != 0) + errno = error; + return (ret); +} + +static void +utx_active_init(const struct futx *fu) +{ + int fd; + + /* Initialize utx.active with a single BOOT_TIME record. */ + fd = _open(_PATH_UTX_ACTIVE, O_CREAT|O_RDWR|O_TRUNC, 0644); + if (fd < 0) + return; + _write(fd, fu, sizeof(*fu)); + _close(fd); +} + +static void +utx_active_purge(void) +{ + + truncate(_PATH_UTX_ACTIVE, 0); +} + +static int +utx_lastlogin_add(const struct futx *fu) +{ + struct futx fe; + FILE *fp; + int error, ret; + + ret = 0; + + /* + * Write an entry to lastlogin. Overwrite the entry if the + * current user already has an entry. If not, append a new + * entry. + */ + fp = futx_open(_PATH_UTX_LASTLOGIN); + if (fp == NULL) + return (-1); + while (fread(&fe, sizeof fe, 1, fp) == 1) { + if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0) + continue; + + /* Found a previous lastlogin entry for this user. */ + ret = fseeko(fp, -(off_t)sizeof fe, SEEK_CUR); + break; + } + if (ret == -1) + error = errno; + else if (fwrite(fu, sizeof *fu, 1, fp) < 1) { + error = errno; + ret = -1; + } + fclose(fp); + if (ret == -1) + errno = error; + return (ret); +} + +static void +utx_lastlogin_upgrade(void) +{ + struct stat sb; + int fd; + + fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR|O_CLOEXEC, 0644); + if (fd < 0) + return; + + /* + * Truncate broken lastlogin files. In the future we should + * check for older versions of the file format here and try to + * upgrade it. + */ + if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) + ftruncate(fd, 0); + _close(fd); +} + +static int +utx_log_add(const struct futx *fu) +{ + struct iovec vec[2]; + int error, fd; + uint16_t l; + + /* + * Append an entry to the log file. We only need to append + * records to this file, so to conserve space, trim any trailing + * zero-bytes. Prepend a length field, indicating the length of + * the record, excluding the length field itself. + */ + for (l = sizeof(*fu); l > 0 && ((const char *)fu)[l - 1] == '\0'; l--) ; + vec[0].iov_base = &l; + vec[0].iov_len = sizeof(l); + vec[1].iov_base = __DECONST(void *, fu); + vec[1].iov_len = l; + l = htobe16(l); + + fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND|O_CLOEXEC, 0644); + if (fd < 0) + return (-1); + if (_writev(fd, vec, 2) == -1) + error = errno; + else + error = 0; + _close(fd); + if (error != 0) + errno = error; + return (error == 0 ? 0 : 1); +} + +struct utmpx * +pututxline(const struct utmpx *utmpx) +{ + struct futx fu; + int bad; + + bad = 0; + + utx_to_futx(utmpx, &fu); + + switch (fu.fu_type) { + case BOOT_TIME: + utx_active_init(&fu); + utx_lastlogin_upgrade(); + break; + case SHUTDOWN_TIME: + utx_active_purge(); + break; + case OLD_TIME: + case NEW_TIME: + break; + case USER_PROCESS: + bad |= utx_active_add(&fu); + bad |= utx_lastlogin_add(&fu); + break; +#if 0 /* XXX: Are these records of any use to us? */ + case INIT_PROCESS: + case LOGIN_PROCESS: + bad |= utx_active_add(&fu); + break; +#endif + case DEAD_PROCESS: + /* + * In case writing a logout entry fails, never attempt + * to write it to utx.log. The logout entry's ut_id + * might be invalid. + */ + if (utx_active_remove(&fu) != 0) + return (NULL); + break; + default: + errno = EINVAL; + return (NULL); + } + + bad |= utx_log_add(&fu); + return (bad ? NULL : futx_to_utx(&fu)); +} diff --git a/lib/libc/gen/pw_scan.c b/lib/libc/gen/pw_scan.c new file mode 100644 index 000000000000..35072d7c1b59 --- /dev/null +++ b/lib/libc/gen/pw_scan.c @@ -0,0 +1,222 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This module is used to "verify" password entries by chpass(1) and + * pwd_mkdb(8). + */ + +#include <sys/param.h> + +#include <err.h> +#include <errno.h> +#include <pwd.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> + +#include "pw_scan.h" + +/* + * Some software assumes that IDs are short. We should emit warnings + * for id's which cannot be stored in a short, but we are more liberal + * by default, warning for IDs greater than USHRT_MAX. + * + * If pw_big_ids_warning is -1 on entry to pw_scan(), it will be set based + * on the existence of PW_SCAN_BIG_IDS in the environment. + * + * It is believed all baseline system software that can not handle the + * normal ID sizes is now gone so pw_big_ids_warning is disabled for now. + * But the code has been left in place in case end-users want to re-enable + * it and/or for the next time the ID sizes get bigger but pieces of the + * system lag behind. + */ +static int pw_big_ids_warning = 0; + +void +__pw_initpwd(struct passwd *pwd) +{ + static char nul[] = ""; + + memset(pwd, 0, sizeof(*pwd)); + pwd->pw_uid = (uid_t)-1; /* Considered least likely to lead to */ + pwd->pw_gid = (gid_t)-1; /* a security issue. */ + pwd->pw_name = nul; + pwd->pw_passwd = nul; + pwd->pw_class = nul; + pwd->pw_gecos = nul; + pwd->pw_dir = nul; + pwd->pw_shell = nul; +} + +int +__pw_scan(char *bp, struct passwd *pw, int flags) +{ + uid_t id; + int root; + char *ep, *p, *sh; + unsigned long temp; + + if (pw_big_ids_warning == -1) + pw_big_ids_warning = getenv("PW_SCAN_BIG_IDS") == NULL ? 1 : 0; + + pw->pw_fields = 0; + if (!(pw->pw_name = strsep(&bp, ":"))) /* login */ + goto fmt; + root = !strcmp(pw->pw_name, "root"); + if (pw->pw_name[0] && (pw->pw_name[0] != '+' || pw->pw_name[1] == '\0')) + pw->pw_fields |= _PWF_NAME; + + if (!(pw->pw_passwd = strsep(&bp, ":"))) /* passwd */ + goto fmt; + if (pw->pw_passwd[0]) + pw->pw_fields |= _PWF_PASSWD; + + if (!(p = strsep(&bp, ":"))) /* uid */ + goto fmt; + if (p[0]) + pw->pw_fields |= _PWF_UID; + else { + if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { + if (flags & _PWSCAN_WARN) + warnx("no uid for user %s", pw->pw_name); + return (0); + } + } + errno = 0; + temp = strtoul(p, &ep, 10); + if ((temp == ULONG_MAX && errno == ERANGE) || temp > UID_MAX) { + if (flags & _PWSCAN_WARN) + warnx("%s > max uid value (%u)", p, UID_MAX); + return (0); + } + id = temp; + if (*ep != '\0') { + if (flags & _PWSCAN_WARN) + warnx("%s uid is incorrect", p); + return (0); + } + if (root && id) { + if (flags & _PWSCAN_WARN) + warnx("root uid should be 0"); + return (0); + } + if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) { + warnx("%s > recommended max uid value (%u)", p, USHRT_MAX); + /*return (0);*/ /* THIS SHOULD NOT BE FATAL! */ + } + pw->pw_uid = id; + + if (!(p = strsep(&bp, ":"))) /* gid */ + goto fmt; + if (p[0]) + pw->pw_fields |= _PWF_GID; + else { + if (pw->pw_name[0] != '+' && pw->pw_name[0] != '-') { + if (flags & _PWSCAN_WARN) + warnx("no gid for user %s", pw->pw_name); + return (0); + } + } + errno = 0; + temp = strtoul(p, &ep, 10); + if ((temp == ULONG_MAX && errno == ERANGE) || temp > GID_MAX) { + if (flags & _PWSCAN_WARN) + warnx("%s > max gid value (%u)", p, GID_MAX); + return (0); + } + id = temp; + if (*ep != '\0') { + if (flags & _PWSCAN_WARN) + warnx("%s gid is incorrect", p); + return (0); + } + if (flags & _PWSCAN_WARN && pw_big_ids_warning && id > USHRT_MAX) { + warnx("%s > recommended max gid value (%u)", p, USHRT_MAX); + /* return (0); This should not be fatal! */ + } + pw->pw_gid = id; + + if (flags & _PWSCAN_MASTER ) { + if (!(pw->pw_class = strsep(&bp, ":"))) /* class */ + goto fmt; + if (pw->pw_class[0]) + pw->pw_fields |= _PWF_CLASS; + + if (!(p = strsep(&bp, ":"))) /* change */ + goto fmt; + if (p[0]) + pw->pw_fields |= _PWF_CHANGE; + pw->pw_change = atol(p); + + if (!(p = strsep(&bp, ":"))) /* expire */ + goto fmt; + if (p[0]) + pw->pw_fields |= _PWF_EXPIRE; + pw->pw_expire = atol(p); + } + if (!(pw->pw_gecos = strsep(&bp, ":"))) /* gecos */ + goto fmt; + if (pw->pw_gecos[0]) + pw->pw_fields |= _PWF_GECOS; + + if (!(pw->pw_dir = strsep(&bp, ":"))) /* directory */ + goto fmt; + if (pw->pw_dir[0]) + pw->pw_fields |= _PWF_DIR; + + if (!(pw->pw_shell = strsep(&bp, ":"))) /* shell */ + goto fmt; + + p = pw->pw_shell; + if (root && *p) { /* empty == /bin/sh */ + for (setusershell();;) { + if (!(sh = getusershell())) { + if (flags & _PWSCAN_WARN) + warnx("warning, unknown root shell"); + break; + } + if (!strcmp(p, sh)) + break; + } + endusershell(); + } + if (p[0]) + pw->pw_fields |= _PWF_SHELL; + + if ((p = strsep(&bp, ":"))) { /* too many */ +fmt: + if (flags & _PWSCAN_WARN) + warnx("corrupted entry"); + return (0); + } + return (1); +} diff --git a/lib/libc/gen/pw_scan.h b/lib/libc/gen/pw_scan.h new file mode 100644 index 000000000000..63457a382821 --- /dev/null +++ b/lib/libc/gen/pw_scan.h @@ -0,0 +1,36 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define _PWSCAN_MASTER 0x01 +#define _PWSCAN_WARN 0x02 + +extern void __pw_initpwd(struct passwd *); +extern int __pw_scan(char *, struct passwd *, int); diff --git a/lib/libc/gen/raise.3 b/lib/libc/gen/raise.3 new file mode 100644 index 000000000000..c74777e7faa9 --- /dev/null +++ b/lib/libc/gen/raise.3 @@ -0,0 +1,70 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd May 7, 2010 +.Dt RAISE 3 +.Os +.Sh NAME +.Nm raise +.Nd send a signal to the current thread +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In signal.h +.Ft int +.Fn raise "int sig" +.Sh DESCRIPTION +The +.Fn raise +function sends the signal +.Fa sig +to the current thread. +.Sh RETURN VALUES +.Rv -std raise +.Sh ERRORS +The +.Fn raise +function +may fail and set +.Va errno +for any of the errors specified for the +library functions +.Xr getpid 2 +and +.Xr kill 2 . +.Sh SEE ALSO +.Xr kill 2 +.Sh STANDARDS +The +.Fn raise +function +conforms to +.St -isoC . diff --git a/lib/libc/gen/raise.c b/lib/libc/gen/raise.c new file mode 100644 index 000000000000..9829de18dcdc --- /dev/null +++ b/lib/libc/gen/raise.c @@ -0,0 +1,49 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <signal.h> +#include <unistd.h> + +#include "libc_private.h" + +__weak_reference(__raise, raise); +__weak_reference(__raise, _raise); +int __raise(int); + +int +__raise(int s) +{ + long id; + + if (__sys_thr_self(&id) == -1) + return (-1); + return (__sys_thr_kill(id, s)); +} diff --git a/lib/libc/gen/rand48.3 b/lib/libc/gen/rand48.3 new file mode 100644 index 000000000000..3ea649354270 --- /dev/null +++ b/lib/libc/gen/rand48.3 @@ -0,0 +1,190 @@ +.\" Copyright (c) 1993 Martin Birgmeier +.\" All rights reserved. +.\" +.\" You may redistribute unmodified or modified versions of this source +.\" code provided that the above copyright notice and this and the +.\" following conditions are retained. +.\" +.\" This software is provided ``as is'', and comes with no warranties +.\" of any kind. I shall in no event be liable for anything that happens +.\" to anyone/anything when using this software. +.\" +.Dd September 11, 2025 +.Dt RAND48 3 +.Os +.Sh NAME +.Nm drand48 , +.Nm erand48 , +.Nm lrand48 , +.Nm nrand48 , +.Nm mrand48 , +.Nm jrand48 , +.Nm srand48 , +.Nm seed48 , +.Nm lcong48 +.Nd pseudo random number generators and initialization routines +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stdlib.h +.Ft double +.Fn drand48 void +.Ft double +.Fn erand48 "unsigned short xseed[3]" +.Ft long +.Fn lrand48 void +.Ft long +.Fn nrand48 "unsigned short xseed[3]" +.Ft long +.Fn mrand48 void +.Ft long +.Fn jrand48 "unsigned short xseed[3]" +.Ft void +.Fn srand48 "long seed" +.Ft "unsigned short *" +.Fn seed48 "unsigned short xseed[3]" +.Ft void +.Fn lcong48 "unsigned short p[7]" +.Sh DESCRIPTION +.Bf -symbolic +The functions described in this manual page are not cryptographically +secure. +Cryptographic applications should use +.Xr arc4random 3 +instead. +.Ef +.Pp +The +.Fn rand48 +family of functions generates pseudo-random numbers using a linear +congruential algorithm working on integers 48 bits in size. +The +particular formula employed is +r(n+1) = (a * r(n) + c) mod m +where the default values are +for the multiplicand a = 0x5deece66d = 25214903917 and +the addend c = 0xb = 11. +The modulo is always fixed at m = 2 ** 48. +r(n) is called the seed of the random number generator. +.Pp +For all the six generator routines described next, the first +computational step is to perform a single iteration of the algorithm. +.Pp +The +.Fn drand48 +and +.Fn erand48 +functions +return values of type double. +The full 48 bits of r(n+1) are +loaded into the mantissa of the returned value, with the exponent set +such that the values produced lie in the interval [0.0, 1.0). +.Pp +The +.Fn lrand48 +and +.Fn nrand48 +functions +return values of type long in the range +[0, 2**31-1]. +The high-order (31) bits of +r(n+1) are loaded into the lower bits of the returned value, with +the topmost (sign) bit set to zero. +.Pp +The +.Fn mrand48 +and +.Fn jrand48 +functions +return values of type long in the range +[-2**31, 2**31-1]. +The high-order (32) bits of +r(n+1) are loaded into the returned value. +.Pp +The +.Fn drand48 , +.Fn lrand48 , +and +.Fn mrand48 +functions +use an internal buffer to store r(n). +For these functions +the initial value of r(0) = 0x1234abcd330e = 20017429951246. +.Pp +On the other hand, +.Fn erand48 , +.Fn nrand48 , +and +.Fn jrand48 +use a user-supplied buffer to store the seed r(n), +which consists of an array of 3 shorts, where the zeroth member +holds the least significant bits. +.Pp +All functions share the same multiplicand and addend. +.Pp +The +.Fn srand48 +function +is used to initialize the internal buffer r(n) of +.Fn drand48 , +.Fn lrand48 , +and +.Fn mrand48 +such that the 32 bits of the seed value are copied into the upper 32 bits +of r(n), with the lower 16 bits of r(n) arbitrarily being set to 0x330e. +Additionally, the constant multiplicand and addend of the algorithm are +reset to the default values given above. +.Pp +The +.Fn seed48 +function +also initializes the internal buffer r(n) of +.Fn drand48 , +.Fn lrand48 , +and +.Fn mrand48 , +but here all 48 bits of the seed can be specified in an array of 3 shorts, +where the zeroth member specifies the lowest bits. +Again, +the constant multiplicand and addend of the algorithm are +reset to the default values given above. +The +.Fn seed48 +function +returns a pointer to an array of 3 shorts which contains the old seed. +This array is statically allocated, thus its contents are lost after +each new call to +.Fn seed48 . +.Pp +Finally, +.Fn lcong48 +allows full control over the multiplicand and addend used in +.Fn drand48 , +.Fn erand48 , +.Fn lrand48 , +.Fn nrand48 , +.Fn mrand48 , +and +.Fn jrand48 , +and the seed used in +.Fn drand48 , +.Fn lrand48 , +and +.Fn mrand48 . +An array of 7 shorts is passed as argument; the first three shorts are +used to initialize the seed; the second three are used to initialize the +multiplicand; and the last short is used to initialize the addend. +It is thus not possible to use values greater than 0xffff as the addend. +.Pp +Note that all three methods of seeding the random number generator +always also set the multiplicand and addend for any of the six +generator calls. +.Sh SEE ALSO +.Xr arc4random 3 , +.Xr rand 3 , +.Xr random 3 +.Sh STANDARDS +The functions described in this page are expected to conform to +.St -p1003.1-2008 . +.Sh AUTHORS +.An Martin Birgmeier diff --git a/lib/libc/gen/rand48.h b/lib/libc/gen/rand48.h new file mode 100644 index 000000000000..d3326e851491 --- /dev/null +++ b/lib/libc/gen/rand48.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#ifndef _RAND48_H_ +#define _RAND48_H_ + +#include <sys/types.h> +#include <math.h> +#include <stdlib.h> + +#include "fpmath.h" + +#define RAND48_SEED_0 (0x330e) +#define RAND48_SEED_1 (0xabcd) +#define RAND48_SEED_2 (0x1234) +#define RAND48_MULT_0 (0xe66d) +#define RAND48_MULT_1 (0xdeec) +#define RAND48_MULT_2 (0x0005) +#define RAND48_ADD (0x000b) + +typedef uint64_t uint48; + +extern uint48 _rand48_seed; +extern uint48 _rand48_mult; +extern uint48 _rand48_add; + +#define TOUINT48(x, y, z) \ + ((uint48)(x) + (((uint48)(y)) << 16) + (((uint48)(z)) << 32)) + +#define RAND48_SEED TOUINT48(RAND48_SEED_0, RAND48_SEED_1, RAND48_SEED_2) +#define RAND48_MULT TOUINT48(RAND48_MULT_0, RAND48_MULT_1, RAND48_MULT_2) + +#define LOADRAND48(l, x) do { \ + (l) = TOUINT48((x)[0], (x)[1], (x)[2]); \ +} while (0) + +#define STORERAND48(l, x) do { \ + (x)[0] = (unsigned short)(l); \ + (x)[1] = (unsigned short)((l) >> 16); \ + (x)[2] = (unsigned short)((l) >> 32); \ +} while (0) + +#define _DORAND48(l) do { \ + (l) = (l) * _rand48_mult + _rand48_add; \ +} while (0) + +#define DORAND48(l, x) do { \ + LOADRAND48(l, x); \ + _DORAND48(l); \ + STORERAND48(l, x); \ +} while (0) + +#define ERAND48_BEGIN \ + union { \ + union IEEEd2bits ieee; \ + uint64_t u64; \ + } u; \ + int s + +/* + * Optimization for speed: assume doubles are IEEE 754 and use bit fiddling + * rather than converting to double. Specifically, clamp the result to 48 bits + * and convert to a double in [0.0, 1.0) via division by 2^48. Normalize by + * shifting the most significant bit into the implicit one position and + * adjusting the exponent accordingly. The store to the exponent field + * overwrites the implicit one. + */ +#define ERAND48_END(x) do { \ + u.u64 = ((x) & 0xffffffffffffULL); \ + if (u.u64 == 0) \ + return (0.0); \ + u.u64 <<= 5; \ + for (s = 0; !(u.u64 & (1LL << 52)); s++, u.u64 <<= 1) \ + ; \ + u.ieee.bits.exp = 1022 - s; \ + return (u.ieee.d); \ +} while (0) + +#endif /* _RAND48_H_ */ diff --git a/lib/libc/gen/readdir-compat11.c b/lib/libc/gen/readdir-compat11.c new file mode 100644 index 000000000000..606e15bd7b36 --- /dev/null +++ b/lib/libc/gen/readdir-compat11.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * From: FreeBSD: head/lib/libc/gen/readdir.c 314436 2017-02-28 23:42:47Z imp + */ + +#include "namespace.h" +#include <sys/param.h> +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "gen-private.h" +#include "telldir.h" + +#include "gen-compat.h" + +static bool +freebsd11_cvtdirent(struct freebsd11_dirent *dstdp, struct dirent *srcdp) +{ + + if (srcdp->d_namlen >= sizeof(dstdp->d_name)) + return (false); + dstdp->d_type = srcdp->d_type; + dstdp->d_namlen = srcdp->d_namlen; + dstdp->d_fileno = srcdp->d_fileno; /* truncate */ + dstdp->d_reclen = FREEBSD11_DIRSIZ(dstdp); + bcopy(srcdp->d_name, dstdp->d_name, dstdp->d_namlen); + bzero(dstdp->d_name + dstdp->d_namlen, + dstdp->d_reclen - offsetof(struct freebsd11_dirent, d_name) - + dstdp->d_namlen); + return (true); +} + +struct freebsd11_dirent * +freebsd11_readdir(DIR *dirp) +{ + struct freebsd11_dirent *dstdp; + struct dirent *dp; + + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + dp = _readdir_unlocked(dirp, RDU_SKIP); + if (dp != NULL) { + if (dirp->dd_compat_de == NULL) + dirp->dd_compat_de = malloc(sizeof(struct + freebsd11_dirent)); + if (freebsd11_cvtdirent(dirp->dd_compat_de, dp)) + dstdp = dirp->dd_compat_de; + else + dstdp = NULL; + } else + dstdp = NULL; + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); + + return (dstdp); +} + +int +freebsd11_readdir_r(DIR *dirp, struct freebsd11_dirent *entry, + struct freebsd11_dirent **result) +{ + struct dirent xentry, *xresult; + int error; + + error = __readdir_r(dirp, &xentry, &xresult); + if (error != 0) + return (error); + if (xresult != NULL) { + if (freebsd11_cvtdirent(entry, &xentry)) + *result = entry; + else /* should not happen due to RDU_SHORT */ + *result = NULL; + } else + *result = NULL; + return (0); +} + +__sym_compat(readdir, freebsd11_readdir, FBSD_1.0); +__sym_compat(readdir_r, freebsd11_readdir_r, FBSD_1.0); diff --git a/lib/libc/gen/readdir.c b/lib/libc/gen/readdir.c new file mode 100644 index 000000000000..94d2b2e8d877 --- /dev/null +++ b/lib/libc/gen/readdir.c @@ -0,0 +1,138 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "gen-private.h" +#include "telldir.h" + +/* + * get next entry in a directory. + */ +struct dirent * +_readdir_unlocked(DIR *dirp, int flags) +{ + struct dirent *dp; + off_t initial_seek; + size_t initial_loc = 0; + ssize_t ret; + + for (;;) { + if (dirp->dd_loc >= dirp->dd_size) { + if (dirp->dd_flags & __DTF_READALL) + return (NULL); + initial_loc = dirp->dd_loc; + dirp->dd_flags &= ~__DTF_SKIPREAD; + dirp->dd_loc = 0; + } + if (dirp->dd_loc == 0 && + !(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) { + dirp->dd_size = 0; + initial_seek = dirp->dd_seek; + ret = _getdirentries(dirp->dd_fd, + dirp->dd_buf, dirp->dd_len, &dirp->dd_seek); + if (ret <= 0) + return (NULL); + dirp->dd_size = (size_t)ret; + _fixtelldir(dirp, initial_seek, initial_loc); + } + dirp->dd_flags &= ~__DTF_SKIPREAD; + dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc); + if ((long)dp & 03L) /* bogus pointer check */ + return (NULL); + if (dp->d_reclen <= 0 || + dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc) + return (NULL); + dirp->dd_loc += dp->d_reclen; + if (dp->d_ino == 0 && (flags & RDU_SKIP) != 0) + continue; + if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW)) + continue; + if (dp->d_namlen >= sizeof(dp->d_name) && + (flags & RDU_SHORT) != 0) + continue; + return (dp); + } +} + +struct dirent * +readdir(DIR *dirp) +{ + struct dirent *dp; + + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + dp = _readdir_unlocked(dirp, RDU_SKIP); + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); + return (dp); +} + +int +__readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result) +{ + struct dirent *dp; + int saved_errno; + + saved_errno = errno; + errno = 0; + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + dp = _readdir_unlocked(dirp, RDU_SKIP | RDU_SHORT); + if (dp != NULL) + memcpy(entry, dp, _GENERIC_DIRSIZ(dp)); + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); + + if (errno != 0) { + if (dp == NULL) + return (errno); + } else + errno = saved_errno; + + if (dp != NULL) + *result = entry; + else + *result = NULL; + + return (0); +} + +__strong_reference(__readdir_r, readdir_r); +__warn_references(readdir_r, + "warning: this program uses readdir_r(), which is unsafe."); diff --git a/lib/libc/gen/readpassphrase.3 b/lib/libc/gen/readpassphrase.3 new file mode 100644 index 000000000000..5703ba5f1aaf --- /dev/null +++ b/lib/libc/gen/readpassphrase.3 @@ -0,0 +1,181 @@ +.\" $OpenBSD: readpassphrase.3,v 1.17 2007/05/31 19:19:28 jmc Exp $ +.\" +.\" Copyright (c) 2000, 2002 Todd C. Miller <Todd.Miller@courtesan.com> +.\" +.\" Permission to use, copy, modify, and distribute this software for any +.\" purpose with or without fee is hereby granted, provided that the above +.\" copyright notice and this permission notice appear in all copies. +.\" +.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +.\" +.\" Sponsored in part by the Defense Advanced Research Projects +.\" Agency (DARPA) and Air Force Research Laboratory, Air Force +.\" Materiel Command, USAF, under agreement number F39502-99-1-0512. +.\" +.Dd May 31, 2007 +.Dt READPASSPHRASE 3 +.Os +.Sh NAME +.Nm readpassphrase +.Nd get a passphrase from the user +.Sh SYNOPSIS +.In readpassphrase.h +.Ft "char *" +.Fn readpassphrase "const char *prompt" "char *buf" "size_t bufsiz" "int flags" +.Sh DESCRIPTION +The +.Fn readpassphrase +function displays a prompt to, and reads in a passphrase from, +.Pa /dev/tty . +If this file is inaccessible +and the +.Dv RPP_REQUIRE_TTY +flag is not set, +.Fn readpassphrase +displays the prompt on the standard error output and reads from the standard +input. +In this case it is generally not possible to turn off echo. +.Pp +Up to +.Fa bufsiz +\- 1 characters (one is for the +.Dv NUL ) +are read into the provided buffer +.Fa buf . +Any additional +characters and the terminating newline (or return) character are discarded. +.Pp +The +.Fn readpassphrase +function +takes the following optional +.Fa flags : +.Pp +.Bl -tag -width ".Dv RPP_REQUIRE_TTY" -compact +.It Dv RPP_ECHO_OFF +turn off echo (default behavior) +.It Dv RPP_ECHO_ON +leave echo on +.It Dv RPP_REQUIRE_TTY +fail if there is no tty +.It Dv RPP_FORCELOWER +force input to lower case +.It Dv RPP_FORCEUPPER +force input to upper case +.It Dv RPP_SEVENBIT +strip the high bit from input +.It Dv RPP_STDIN +force read of passphrase from stdin +.El +.Pp +The calling process should zero the passphrase as soon as possible to +avoid leaving the cleartext passphrase visible in the process's address +space. +.Sh RETURN VALUES +Upon successful completion, +.Fn readpassphrase +returns a pointer to the NUL-terminated passphrase. +If an error is encountered, the terminal state is restored and +a +.Dv NULL +pointer is returned. +.Sh FILES +.Bl -tag -width ".Pa /dev/tty" -compact +.It Pa /dev/tty +.El +.Sh EXAMPLES +The following code fragment will read a passphrase from +.Pa /dev/tty +into the buffer +.Fa passbuf . +.Bd -literal -offset indent +char passbuf[1024]; + +\&... + +if (readpassphrase("Response: ", passbuf, sizeof(passbuf), + RPP_REQUIRE_TTY) == NULL) + errx(1, "unable to read passphrase"); + +if (compare(transform(passbuf), epass) != 0) + errx(1, "bad passphrase"); + +\&... + +memset(passbuf, 0, sizeof(passbuf)); +.Ed +.Sh ERRORS +.Bl -tag -width Er +.It Bq Er EINTR +The +.Fn readpassphrase +function was interrupted by a signal. +.It Bq Er EINVAL +The +.Ar bufsiz +argument was zero. +.It Bq Er EIO +The process is a member of a background process attempting to read +from its controlling terminal, the process is ignoring or blocking +the +.Dv SIGTTIN +signal, or the process group is orphaned. +.It Bq Er EMFILE +The process has already reached its limit for open file descriptors. +.It Bq Er ENFILE +The system file table is full. +.It Bq Er ENOTTY +There is no controlling terminal and the +.Dv RPP_REQUIRE_TTY +flag was specified. +.El +.Sh SIGNALS +The +.Fn readpassphrase +function +will catch the following signals: +.Bd -literal -offset indent +SIGALRM SIGHUP SIGINT +SIGPIPE SIGQUIT SIGTERM +SIGTSTP SIGTTIN SIGTTOU +.Ed +.Pp +When one of the above signals is intercepted, terminal echo will +be restored if it had previously been turned off. +If a signal handler was installed for the signal when +.Fn readpassphrase +was called, that handler is then executed. +If no handler was previously installed for the signal then the +default action is taken as per +.Xr sigaction 2 . +.Pp +The +.Dv SIGTSTP , SIGTTIN +and +.Dv SIGTTOU +signals (stop signals generated from keyboard or due to terminal I/O +from a background process) are treated specially. +When the process is resumed after it has been stopped, +.Fn readpassphrase +will reprint the prompt and the user may then enter a passphrase. +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr getpass 3 +.Sh STANDARDS +The +.Fn readpassphrase +function is an +extension and should not be used if portability is desired. +.Sh HISTORY +The +.Fn readpassphrase +function first appeared in +.Fx 4.6 +and +.Ox 2.9 . diff --git a/lib/libc/gen/readpassphrase.c b/lib/libc/gen/readpassphrase.c new file mode 100644 index 000000000000..5319d3e634af --- /dev/null +++ b/lib/libc/gen/readpassphrase.c @@ -0,0 +1,200 @@ +/* $OpenBSD: readpassphrase.c,v 1.24 2013/11/24 23:51:29 deraadt Exp $ */ + +/* + * Copyright (c) 2000-2002, 2007, 2010 + * Todd C. Miller <Todd.Miller@courtesan.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ + +#include "namespace.h" +#include <ctype.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <pwd.h> +#include <signal.h> +#include <string.h> +#include <termios.h> +#include <unistd.h> +#include <readpassphrase.h> +#include "un-namespace.h" +#include "libc_private.h" + +static volatile sig_atomic_t signo[NSIG]; + +static void handler(int); + +char * +readpassphrase(const char *prompt, char *buf, size_t bufsiz, int flags) +{ + ssize_t nr; + int input, output, save_errno, i, need_restart, input_is_tty; + char ch, *p, *end; + struct termios term, oterm; + struct sigaction sa, savealrm, saveint, savehup, savequit, saveterm; + struct sigaction savetstp, savettin, savettou, savepipe; + + /* I suppose we could alloc on demand in this case (XXX). */ + if (bufsiz == 0) { + errno = EINVAL; + return(NULL); + } + +restart: + for (i = 0; i < NSIG; i++) + signo[i] = 0; + nr = -1; + save_errno = 0; + need_restart = 0; + /* + * Read and write to /dev/tty if available. If not, read from + * stdin and write to stderr unless a tty is required. + */ + input_is_tty = 0; + if (!(flags & RPP_STDIN)) { + input = output = _open(_PATH_TTY, O_RDWR | O_CLOEXEC); + if (input == -1) { + if (flags & RPP_REQUIRE_TTY) { + errno = ENOTTY; + return(NULL); + } + input = STDIN_FILENO; + output = STDERR_FILENO; + } else { + input_is_tty = 1; + } + } else { + input = STDIN_FILENO; + output = STDERR_FILENO; + } + + /* + * Turn off echo if possible. + * If we are using a tty but are not the foreground pgrp this will + * generate SIGTTOU, so do it *before* installing the signal handlers. + */ + if (input_is_tty && tcgetattr(input, &oterm) == 0) { + memcpy(&term, &oterm, sizeof(term)); + if (!(flags & RPP_ECHO_ON)) + term.c_lflag &= ~(ECHO | ECHONL); + if (term.c_cc[VSTATUS] != _POSIX_VDISABLE) + term.c_cc[VSTATUS] = _POSIX_VDISABLE; + (void)tcsetattr(input, TCSAFLUSH|TCSASOFT, &term); + } else { + memset(&term, 0, sizeof(term)); + term.c_lflag |= ECHO; + memset(&oterm, 0, sizeof(oterm)); + oterm.c_lflag |= ECHO; + } + + /* + * Catch signals that would otherwise cause the user to end + * up with echo turned off in the shell. Don't worry about + * things like SIGXCPU and SIGVTALRM for now. + */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; /* don't restart system calls */ + sa.sa_handler = handler; + (void)__libc_sigaction(SIGALRM, &sa, &savealrm); + (void)__libc_sigaction(SIGHUP, &sa, &savehup); + (void)__libc_sigaction(SIGINT, &sa, &saveint); + (void)__libc_sigaction(SIGPIPE, &sa, &savepipe); + (void)__libc_sigaction(SIGQUIT, &sa, &savequit); + (void)__libc_sigaction(SIGTERM, &sa, &saveterm); + (void)__libc_sigaction(SIGTSTP, &sa, &savetstp); + (void)__libc_sigaction(SIGTTIN, &sa, &savettin); + (void)__libc_sigaction(SIGTTOU, &sa, &savettou); + + if (!(flags & RPP_STDIN)) + (void)_write(output, prompt, strlen(prompt)); + end = buf + bufsiz - 1; + p = buf; + while ((nr = _read(input, &ch, 1)) == 1 && ch != '\n' && ch != '\r') { + if (p < end) { + if ((flags & RPP_SEVENBIT)) + ch &= 0x7f; + if (isalpha((unsigned char)ch)) { + if ((flags & RPP_FORCELOWER)) + ch = (char)tolower((unsigned char)ch); + if ((flags & RPP_FORCEUPPER)) + ch = (char)toupper((unsigned char)ch); + } + *p++ = ch; + } + } + *p = '\0'; + save_errno = errno; + if (!(term.c_lflag & ECHO)) + (void)_write(output, "\n", 1); + + /* Restore old terminal settings and signals. */ + if (memcmp(&term, &oterm, sizeof(term)) != 0) { + while (tcsetattr(input, TCSAFLUSH|TCSASOFT, &oterm) == -1 && + errno == EINTR && !signo[SIGTTOU]) + continue; + } + (void)__libc_sigaction(SIGALRM, &savealrm, NULL); + (void)__libc_sigaction(SIGHUP, &savehup, NULL); + (void)__libc_sigaction(SIGINT, &saveint, NULL); + (void)__libc_sigaction(SIGQUIT, &savequit, NULL); + (void)__libc_sigaction(SIGPIPE, &savepipe, NULL); + (void)__libc_sigaction(SIGTERM, &saveterm, NULL); + (void)__libc_sigaction(SIGTSTP, &savetstp, NULL); + (void)__libc_sigaction(SIGTTIN, &savettin, NULL); + (void)__libc_sigaction(SIGTTOU, &savettou, NULL); + if (input_is_tty) + (void)_close(input); + + /* + * If we were interrupted by a signal, resend it to ourselves + * now that we have restored the signal handlers. + */ + for (i = 0; i < NSIG; i++) { + if (signo[i]) { + kill(getpid(), i); + switch (i) { + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + need_restart = 1; + } + } + } + if (need_restart) + goto restart; + + if (save_errno) + errno = save_errno; + return(nr == -1 ? NULL : buf); +} + +char * +getpass(const char *prompt) +{ + static char buf[_PASSWORD_LEN + 1]; + + if (readpassphrase(prompt, buf, sizeof(buf), RPP_ECHO_OFF) == NULL) + buf[0] = '\0'; + return(buf); +} + +static void handler(int s) +{ + + signo[s] = 1; +} diff --git a/lib/libc/gen/rewinddir.c b/lib/libc/gen/rewinddir.c new file mode 100644 index 000000000000..df829e98d138 --- /dev/null +++ b/lib/libc/gen/rewinddir.c @@ -0,0 +1,60 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <dirent.h> +#include <pthread.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "gen-private.h" +#include "telldir.h" + +void +rewinddir(DIR *dirp) +{ + + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + dirp->dd_flags &= ~__DTF_SKIPREAD; /* current contents are invalid */ + if (dirp->dd_flags & __DTF_READALL) + _filldir(dirp, false); + else { + (void) lseek(dirp->dd_fd, 0, SEEK_SET); + dirp->dd_seek = 0; + } + dirp->dd_loc = 0; + _reclaim_telldir(dirp); + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); +} diff --git a/lib/libc/gen/rtld_get_var.3 b/lib/libc/gen/rtld_get_var.3 new file mode 100644 index 000000000000..092114e86d78 --- /dev/null +++ b/lib/libc/gen/rtld_get_var.3 @@ -0,0 +1,106 @@ +.\" Copyright (c) 2024 The FreeBSD Foundation +.\" +.\" This documentation was written by +.\" Konstantin Belousov <kib@FreeBSD.org> under sponsorship +.\" from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 31, 2024 +.Dt RTLD_GET_VAR 3 +.Os +.Sh NAME +.Nm rtld_get_var , +.Nm rtld_set_var +.Nd query or change run-time linker parameters after image activation +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/errno.h +.In link.h +.Ft const char * +.Fn rtld_get_var "const char *name" +.Ft int +.Fn rtld_set_var "const char *name" "const char *value" +.Sh DESCRIPTION +The dynamic linker +.Xr rtld 1 +can be configured by setting some environment variables for the process, +before image activation. +Sometimes it is desirable to query the current effective settings or +change them afterward. +.Pp +Since the process environment variables are maintained by higher-level +libraries, the run-time linker cannot access them after the image +activation. +The described functions make it possible to operate on rtld settings. +.Pp +The +.Fn rtld_get_var +function returns the current value of the named parameter. +.Pp +The +.Fn rtld_set_var +functions changes the value of the parameter to the new +.Fa value +value, if possible. +The +.Fa name +argument to both functions is the name of the parameter, which +is same as the corresponding environment variable +.Pq see Xr rtld 1 +but without the +.Ev LD_ +(or +.Ev LD_32_ +or any other ABI-specific) prefix. +.Sh RETURN VALUES +The +.Fn rtld_get_var +returns the current value of the named parameter, or +.Dv NULL +if the name is invalid. +.Pp +The +.Fn rtld_set_var +returns 0 on success, or an integer indicating the error condition +which prevented the operation. +.Sh ERRORS +Possible errors returned from +.Fn rtld_set_var : +.Bl -tag -width Er +.It Bq Er EPERM +The requested change cannot be made at runtime, either because the +runtime linker can only take this parameter at initialization time, +or because the current process is executing with elevated privileges. +.It Bq ENOENT +The supplied parameter +.Fa name +is unknown. +.El +.Sh SEE ALSO +.Xr rtld 1 +.Sh HISTORY +The +.Nm +function first appeared in +.Fx 14.3 . diff --git a/lib/libc/gen/scandir-compat11.c b/lib/libc/gen/scandir-compat11.c new file mode 100644 index 000000000000..96c9b1052b48 --- /dev/null +++ b/lib/libc/gen/scandir-compat11.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * From: FreeBSD: head/lib/libc/gen/scandir.c 317372 2017-04-24 14:56:41Z pfg + */ + +/* + * Scan the directory dirname calling select to make a list of selected + * directory entries then sort using qsort and compare routine dcomp. + * Returns the number of entries and a pointer to a list of pointers to + * struct dirent (through namelist). Returns -1 if there were any errors. + */ + +#include "namespace.h" +#define _WANT_FREEBSD11_DIRENT +#include <dirent.h> +#include <stdlib.h> +#include <string.h> +#include "un-namespace.h" + +#include "gen-compat.h" + +/* + * scandir_b@FBSD_1.4 was never exported from libc.so.7 due to a + * mistake, so there is no use of exporting it now with some earlier + * symbol version. As result, we do not need to implement compat + * function freebsd11_scandir_b(). + */ + +#define SELECT(x) select(x) + +static int freebsd11_scandir_thunk_cmp(const void *p1, const void *p2, + void *thunk); + +int +freebsd11_scandir(const char *dirname, struct freebsd11_dirent ***namelist, + int (*select)(const struct freebsd11_dirent *), + int (*dcomp)(const struct freebsd11_dirent **, + const struct freebsd11_dirent **)) +{ + struct freebsd11_dirent *d, *p, **names = NULL; + size_t arraysz, numitems; + DIR *dirp; + + if ((dirp = opendir(dirname)) == NULL) + return(-1); + + numitems = 0; + arraysz = 32; /* initial estimate of the array size */ + names = (struct freebsd11_dirent **)malloc( + arraysz * sizeof(struct freebsd11_dirent *)); + if (names == NULL) + goto fail; + + while ((d = freebsd11_readdir(dirp)) != NULL) { + if (select != NULL && !SELECT(d)) + continue; /* just selected names */ + /* + * Make a minimum size copy of the data + */ + p = (struct freebsd11_dirent *)malloc(FREEBSD11_DIRSIZ(d)); + if (p == NULL) + goto fail; + p->d_fileno = d->d_fileno; + p->d_type = d->d_type; + p->d_reclen = d->d_reclen; + p->d_namlen = d->d_namlen; + bcopy(d->d_name, p->d_name, p->d_namlen + 1); + /* + * Check to make sure the array has space left and + * realloc the maximum size. + */ + if (numitems >= arraysz) { + struct freebsd11_dirent **names2; + + names2 = reallocarray(names, arraysz, + 2 * sizeof(struct freebsd11_dirent *)); + if (names2 == NULL) { + free(p); + goto fail; + } + names = names2; + arraysz *= 2; + } + names[numitems++] = p; + } + closedir(dirp); + if (numitems && dcomp != NULL) + qsort_r(names, numitems, sizeof(struct freebsd11_dirent *), + freebsd11_scandir_thunk_cmp, &dcomp); + *namelist = names; + return (numitems); + +fail: + while (numitems > 0) + free(names[--numitems]); + free(names); + closedir(dirp); + return (-1); +} + +/* + * Alphabetic order comparison routine for those who want it. + * POSIX 2008 requires that alphasort() uses strcoll(). + */ +int +freebsd11_alphasort(const struct freebsd11_dirent **d1, + const struct freebsd11_dirent **d2) +{ + + return (strcoll((*d1)->d_name, (*d2)->d_name)); +} + +static int +freebsd11_scandir_thunk_cmp(const void *p1, const void *p2, void *thunk) +{ + int (*dc)(const struct freebsd11_dirent **, const struct + freebsd11_dirent **); + + dc = *(int (**)(const struct freebsd11_dirent **, + const struct freebsd11_dirent **))thunk; + return (dc((const struct freebsd11_dirent **)p1, + (const struct freebsd11_dirent **)p2)); +} + +__sym_compat(alphasort, freebsd11_alphasort, FBSD_1.0); +__sym_compat(scandir, freebsd11_scandir, FBSD_1.0); diff --git a/lib/libc/gen/scandir.3 b/lib/libc/gen/scandir.3 new file mode 100644 index 000000000000..3da4500cefb9 --- /dev/null +++ b/lib/libc/gen/scandir.3 @@ -0,0 +1,300 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 25, 2025 +.Dt SCANDIR 3 +.Os +.Sh NAME +.Nm scandir , +.Nm fdscandir , +.Nm scandirat , +.Nm scandir_b , +.Nm fdscandir_b , +.Nm fdscandirat_b , +.Nm alphasort , +.Nm versionsort +.Nd scan a directory +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In dirent.h +.Ft int +.Fo scandir +.Fa "const char *dirname" +.Fa "struct dirent ***namelist" +.Fa "int \*(lp*select\*(rp\*(lpconst struct dirent *\*(rp" +.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp" +.Fc +.Ft int +.Fo fdscandir +.Fa "int dirfd" +.Fa "struct dirent ***namelist" +.Fa "int \*(lp*select\*(rp\*(lpconst struct dirent *\*(rp" +.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp" +.Fc +.Ft int +.Fo scandirat +.Fa "int dirfd" +.Fa "const char *dirname" +.Fa "struct dirent ***namelist" +.Fa "int \*(lp*select\*(rp\*(lpconst struct dirent *\*(rp" +.Fa "int \*(lp*compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp" +.Fc +.Ft int +.Fo scandir_b +.Fa "const char *dirname" +.Fa "struct dirent ***namelist" +.Fa "int \*(lp^select\*(rp\*(lpconst struct dirent *\*(rp" +.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp" +.Fc +.Ft int +.Fo fdscandir_b +.Fa "int dirfd" +.Fa "struct dirent ***namelist" +.Fa "int \*(lp^select\*(rp\*(lpconst struct dirent *\*(rp" +.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp" +.Fc +.Ft int +.Fo scandirat_b +.Fa "int dirfd" +.Fa "const char *dirname" +.Fa "struct dirent ***namelist" +.Fa "int \*(lp^select\*(rp\*(lpconst struct dirent *\*(rp" +.Fa "int \*(lp^compar\*(rp\*(lpconst struct dirent **, const struct dirent **\*(rp" +.Fc +.Ft int +.Fn alphasort "const struct dirent **d1" "const struct dirent **d2" +.Ft int +.Fn versionsort "const struct dirent **d1" "const struct dirent **d2" +.Sh DESCRIPTION +The +.Fn scandir +function +reads the directory +.Fa dirname +and builds an array of pointers to directory +entries using +.Xr malloc 3 . +It returns the number of entries in the array. +A pointer to the array of directory entries is stored in the location +referenced by +.Fa namelist +(even if no entries were selected). +.Pp +The +.Fa select +argument is a pointer to a user supplied subroutine which is called by +.Fn scandir +to select which entries are to be included in the array. +The select routine is passed a +pointer to a directory entry and should return a non-zero +value if the directory entry is to be included in the array. +If +.Fa select +is null, then all the directory entries will be included. +.Pp +The +.Fa compar +argument is a pointer to a user supplied subroutine which is passed to +.Xr qsort 3 +to sort the completed array. +If this pointer is null, the array is not sorted. +.Pp +The +.Fn alphasort +function +is a routine which can be used for the +.Fa compar +argument to sort the array alphabetically using +.Xr strcoll 3 . +.Pp +The +.Fn versionsort +function is a routine which can be used for the +.Fa compar +argument to sort the array naturally using +.Xr strverscmp 3 . +.Pp +The memory allocated for the array can be deallocated with +.Xr free 3 , +by freeing each pointer in the array and then the array itself. +.Pp +The +.Fn fdscandir +function is similar to +.Fn scandir , +but takes a file descriptor referencing a directory instead of a path. +The file descriptor is left open on return, regardless of outcome. +.Pp +The +.Fn scandirat +function is similar to +.Fn scandir , +but takes an additional +.Fa dirfd +argument. +If the supplied +.Fa dirname +is absolute, the function's behavior is identical to that of +.Fn scandir , +the +.Fa dirfd +argument is unused. +If +.Fa dirname +is relative, +.Fa dirfd +must be a valid file descriptor referencing a directory, in +which case the +.Fa dirname +lookup is performed relative to the directory referenced by +.Fa dirfd . +If +.Fa dirfd +has the special value +.Va AT_FDCWD , +then the current process directory is used as the base for +relative lookups. +See +.Xr openat 2 +for additional details. +.Pp +The +.Fn scandir_b , +.Fn fdscandir_b , +and +.Fn scandirat_b +functions behave in the same way as +.Fn scandir , +.Fn fdscandir , +and +.Fn scandirat , +respectively, +but take blocks as arguments instead of function pointers and call +.Fn qsort_b +rather than +.Fn qsort . +.Sh DIAGNOSTICS +The +.Fn scandir , +.Fn fdscandir , +.Fn scandirat , +.Fn scandir_b , +.Fn fdscandir_b , +and +.Fn scandirat_b +functions return the number of directory entries found on succes. +If the directory cannot be opened for reading, an error occurs +while reading the directory, or +.Xr malloc 3 +cannot allocate enough memory to hold all the directory entries, +they return \-1 and set +.Va errno +to an appropriate value. +.Sh ERRORS +The +.Fn scandir , +.Fn scandirat , +.Fn scandir_b , +and +.Fn scandirat_b +functions may fail and set +.Va errno +for any of the errors specified for the +.Xr opendir 3 , +.Xr malloc 3 , +.Xr readdir 3 , +and +.Xr closedir 3 +functions. +.Pp +The +.Fn fdscandir +and +.Fn fdscandir_b +functions may fail and set +.Va errno +for any of the errors specified for the +.Xr fdopendir 3 , +.Xr malloc 3 , +.Xr readdir 3 , +and +.Xr closedir 3 +functions. +.Sh SEE ALSO +.Xr openat 2 , +.Xr directory 3 , +.Xr malloc 3 , +.Xr qsort 3 , +.Xr strcoll 3 , +.Xr strverscmp 3 , +.Xr dir 5 +.Sh STANDARDS +The +.Fn alphasort +and +.Fn scandir +functions are expected to conform to +.St -p1003.1-2008 . +The +.Fn scandirat +and +.Fn versionsort +functions are GNU extensions and conform to no standard. +The +.Fn fdscandir , +.Fn scandir_b , +.Fn fdscandir_b , +and +.Fn scandirat_b +functions are +.Fx +extensions. +.Sh HISTORY +The +.Fn scandir +and +.Fn alphasort +functions appeared in +.Bx 4.2 . +The +.Fn scandir_b +function was added in +.Fx 11.0 . +The +.Fn scandirat +and +.Fn versionsort +functions were added in +.Fx 13.2 . +The +.Fn fdscandir , +.Fn fdscandir_b , +and +.Fn scandirat_b +functions were added in +.Fx 15.0 . diff --git a/lib/libc/gen/scandir.c b/lib/libc/gen/scandir.c new file mode 100644 index 000000000000..fb589f4b36b6 --- /dev/null +++ b/lib/libc/gen/scandir.c @@ -0,0 +1,254 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Scan the directory dirname calling select to make a list of selected + * directory entries then sort using qsort and compare routine dcomp. + * Returns the number of entries and a pointer to a list of pointers to + * struct dirent (through namelist). Returns -1 if there were any errors. + */ + +#include "namespace.h" +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#ifdef I_AM_SCANDIR_B +#include "block_abi.h" +#define SELECT(x) CALL_BLOCK(select, x) +#ifndef __BLOCKS__ +void qsort_b(void *, size_t, size_t, void *); +#endif +#else +#define SELECT(x) select(x) +#endif + +#ifdef I_AM_SCANDIR_B +typedef DECLARE_BLOCK(int, select_block, const struct dirent *); +typedef DECLARE_BLOCK(int, dcomp_block, const struct dirent **, + const struct dirent **); +#else +static int scandir_thunk_cmp(const void *p1, const void *p2, void *thunk); +#endif + +static int +#ifdef I_AM_SCANDIR_B +scandir_dirp_b(DIR *dirp, struct dirent ***namelist, select_block select, + dcomp_block dcomp) +#else +scandir_dirp(DIR *dirp, struct dirent ***namelist, + int (*select)(const struct dirent *), + int (*dcomp)(const struct dirent **, const struct dirent **)) +#endif +{ + struct dirent *d, *p = NULL, **names = NULL, **names2; + size_t arraysz = 32, numitems = 0; + int serrno; + + names = malloc(arraysz * sizeof(*names)); + if (names == NULL) + return (-1); + + while (errno = 0, (d = readdir(dirp)) != NULL) { + if (select != NULL && !SELECT(d)) + continue; /* just selected names */ + /* + * Make a minimum size copy of the data + */ + p = malloc(_GENERIC_DIRSIZ(d)); + if (p == NULL) + goto fail; + p->d_fileno = d->d_fileno; + p->d_type = d->d_type; + p->d_reclen = d->d_reclen; + p->d_namlen = d->d_namlen; + memcpy(p->d_name, d->d_name, p->d_namlen + 1); + /* + * Check to make sure the array has space left and + * realloc the maximum size. + */ + if (numitems >= arraysz) { + arraysz = arraysz * 2; + names2 = reallocarray(names, arraysz, sizeof(*names)); + if (names2 == NULL) + goto fail; + names = names2; + } + names[numitems++] = p; + } + /* + * Since we can't simultaneously return both -1 and a count, we + * must either suppress the error or discard the partial result. + * The latter seems the lesser of two evils. + */ + if (errno != 0) + goto fail; + if (numitems > 0 && dcomp != NULL) { +#ifdef I_AM_SCANDIR_B + qsort_b(names, numitems, sizeof(struct dirent *), + (void *)dcomp); +#else + qsort_r(names, numitems, sizeof(struct dirent *), + scandir_thunk_cmp, &dcomp); +#endif + } + *namelist = names; + return (numitems); + +fail: + serrno = errno; + if (numitems == 0 || names[numitems - 1] != p) + free(p); + while (numitems > 0) + free(names[--numitems]); + free(names); + errno = serrno; + return (-1); +} + +int +#ifdef I_AM_SCANDIR_B +scandir_b(const char *dirname, struct dirent ***namelist, select_block select, + dcomp_block dcomp) +#else +scandir(const char *dirname, struct dirent ***namelist, + int (*select)(const struct dirent *), + int (*dcomp)(const struct dirent **, const struct dirent **)) +#endif +{ + DIR *dirp; + int ret, serrno; + + dirp = opendir(dirname); + if (dirp == NULL) + return (-1); + ret = +#ifdef I_AM_SCANDIR_B + scandir_dirp_b +#else + scandir_dirp +#endif + (dirp, namelist, select, dcomp); + serrno = errno; + closedir(dirp); + errno = serrno; + return (ret); +} + +int +#ifdef I_AM_SCANDIR_B +fdscandir_b(int dirfd, struct dirent ***namelist, select_block select, + dcomp_block dcomp) +#else +fdscandir(int dirfd, struct dirent ***namelist, + int (*select)(const struct dirent *), + int (*dcomp)(const struct dirent **, const struct dirent **)) +#endif +{ + DIR *dirp; + int ret, serrno; + + dirp = fdopendir(dirfd); + if (dirp == NULL) + return (-1); + ret = +#ifdef I_AM_SCANDIR_B + scandir_dirp_b +#else + scandir_dirp +#endif + (dirp, namelist, select, dcomp); + serrno = errno; + fdclosedir(dirp); + errno = serrno; + return (ret); +} + +int +#ifdef I_AM_SCANDIR_B +scandirat_b(int dirfd, const char *dirname, struct dirent ***namelist, + select_block select, dcomp_block dcomp) +#else +scandirat(int dirfd, const char *dirname, struct dirent ***namelist, + int (*select)(const struct dirent *), + int (*dcomp)(const struct dirent **, const struct dirent **)) +#endif +{ + int fd, ret, serrno; + + fd = _openat(dirfd, dirname, O_RDONLY | O_DIRECTORY | O_CLOEXEC); + if (fd == -1) + return (-1); + ret = +#ifdef I_AM_SCANDIR_B + fdscandir_b +#else + fdscandir +#endif + (fd, namelist, select, dcomp); + serrno = errno; + _close(fd); + errno = serrno; + return (ret); +} + +#ifndef I_AM_SCANDIR_B +/* + * Alphabetic order comparison routine for those who want it. + * POSIX 2008 requires that alphasort() uses strcoll(). + */ +int +alphasort(const struct dirent **d1, const struct dirent **d2) +{ + + return (strcoll((*d1)->d_name, (*d2)->d_name)); +} + +int +versionsort(const struct dirent **d1, const struct dirent **d2) +{ + + return (strverscmp((*d1)->d_name, (*d2)->d_name)); +} + +static int +scandir_thunk_cmp(const void *p1, const void *p2, void *thunk) +{ + int (*dc)(const struct dirent **, const struct dirent **); + + dc = *(int (**)(const struct dirent **, const struct dirent **))thunk; + return (dc((const struct dirent **)p1, (const struct dirent **)p2)); +} +#endif diff --git a/lib/libc/gen/scandir_b.c b/lib/libc/gen/scandir_b.c new file mode 100644 index 000000000000..3350ce8227b9 --- /dev/null +++ b/lib/libc/gen/scandir_b.c @@ -0,0 +1,27 @@ +/*- + * Copyright (c) 2014 David Chisnall + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ +#define I_AM_SCANDIR_B +#include "scandir.c" diff --git a/lib/libc/gen/sched_getaffinity.c b/lib/libc/gen/sched_getaffinity.c new file mode 100644 index 000000000000..fce47fbfc0d2 --- /dev/null +++ b/lib/libc/gen/sched_getaffinity.c @@ -0,0 +1,56 @@ +/*- + * Copyright (c) 2021 The FreeBSD Foundation + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define _WANT_P_OSREL +#include <sys/param.h> +#include <errno.h> +#include <sched.h> +#include <string.h> + +#include "libc_private.h" + +int +sched_getaffinity(pid_t pid, size_t cpusetsz, cpuset_t *cpuset) +{ + cpuwhich_t which; + int error; + + if (__getosreldate() < P_OSREL_TIDPID) { + if (pid == 0 || pid > _PID_MAX) + which = CPU_WHICH_TID; + else + which = CPU_WHICH_PID; + } else + which = CPU_WHICH_TIDPID; + + error = cpuset_getaffinity(CPU_LEVEL_WHICH, which, + pid == 0 ? -1 : pid, cpusetsz, cpuset); + if (error == -1 && errno == ERANGE) + errno = EINVAL; + return (error); +} diff --git a/lib/libc/gen/sched_setaffinity.c b/lib/libc/gen/sched_setaffinity.c new file mode 100644 index 000000000000..b878e1affc41 --- /dev/null +++ b/lib/libc/gen/sched_setaffinity.c @@ -0,0 +1,79 @@ +/*- + * Copyright (c) 2021 The FreeBSD Foundation + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define _WANT_P_OSREL +#include <sys/param.h> +#include <sys/sysctl.h> +#include <errno.h> +#include <sched.h> +#include <string.h> + +#include "libc_private.h" + +int +sched_setaffinity(pid_t pid, size_t cpusetsz, const cpuset_t *cpuset) +{ + static int mp_maxid; + cpuwhich_t which; + cpuset_t c; + int error, lbs, cpu; + size_t len, sz; + + if (__getosreldate() < P_OSREL_TIDPID) { + if (pid == 0 || pid > _PID_MAX) + which = CPU_WHICH_TID; + else + which = CPU_WHICH_PID; + } else + which = CPU_WHICH_TIDPID; + + sz = cpusetsz > sizeof(cpuset_t) ? sizeof(cpuset_t) : cpusetsz; + memset(&c, 0, sizeof(c)); + memcpy(&c, cpuset, sz); + + /* Linux ignores high bits */ + if (mp_maxid == 0) { + len = sizeof(mp_maxid); + error = sysctlbyname("kern.smp.maxid", &mp_maxid, &len, + NULL, 0); + if (error == -1) + return (error); + } + lbs = CPU_FLS(&c) - 1; + if (lbs > mp_maxid) { + CPU_FOREACH_ISSET(cpu, &c) + if (cpu > mp_maxid) + CPU_CLR(cpu, &c); + } + error = cpuset_setaffinity(CPU_LEVEL_WHICH, which, + pid == 0 ? -1 : pid, sizeof(cpuset_t), &c); + if (error == -1 && errno == EDEADLK) + errno = EINVAL; + + return (error); +} diff --git a/lib/libc/gen/seed48.c b/lib/libc/gen/seed48.c new file mode 100644 index 000000000000..f57656ce1121 --- /dev/null +++ b/lib/libc/gen/seed48.c @@ -0,0 +1,26 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +unsigned short * +seed48(unsigned short xseed[3]) +{ + static unsigned short sseed[3]; + + STORERAND48(_rand48_seed, sseed); + LOADRAND48(_rand48_seed, xseed); + _rand48_mult = RAND48_MULT; + _rand48_add = RAND48_ADD; + return (sseed); +} diff --git a/lib/libc/gen/seekdir.c b/lib/libc/gen/seekdir.c new file mode 100644 index 000000000000..c796aa7e3550 --- /dev/null +++ b/lib/libc/gen/seekdir.c @@ -0,0 +1,54 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <dirent.h> +#include <pthread.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "gen-private.h" +#include "telldir.h" + +/* + * Seek to an entry in a directory. + * _seekdir is in telldir.c so that it can share opaque data structures. + */ +void +seekdir(DIR *dirp, long loc) +{ + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + _seekdir(dirp, loc); + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); +} diff --git a/lib/libc/gen/sem.c b/lib/libc/gen/sem.c new file mode 100644 index 000000000000..9b0071bc64c0 --- /dev/null +++ b/lib/libc/gen/sem.c @@ -0,0 +1,464 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Some notes about this implementation. + * + * This is mostly a simple implementation of POSIX semaphores that + * does not need threading. Any semaphore created is a kernel-based + * semaphore regardless of the pshared attribute. This is necessary + * because libc's stub for pthread_cond_wait() doesn't really wait, + * and it is not worth the effort impose this behavior on libc. + * + * All functions here are designed to be thread-safe so that a + * threads library need not provide wrappers except to make + * sem_wait() and sem_timedwait() cancellation points or to + * provide a faster userland implementation for non-pshared + * semaphores. + * + * Also, this implementation of semaphores cannot really support + * real pshared semaphores. The sem_t is an allocated object + * and can't be seen by other processes when placed in shared + * memory. It should work across forks as long as the semaphore + * is created before any forks. + * + * The function sem_init() should be overridden by a threads + * library if it wants to provide a different userland version + * of semaphores. The functions sem_wait() and sem_timedwait() + * need to be wrapped to provide cancellation points. The function + * sem_post() may need to be wrapped to be signal-safe. + */ +#include "namespace.h" +#include <sys/types.h> +#include <sys/queue.h> +#include <machine/atomic.h> +#include <errno.h> +#include <sys/umtx.h> +#include <sys/_semaphore.h> +#include <limits.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdlib.h> +#include <time.h> +#include "un-namespace.h" +#include "libc_private.h" + +/* + * Old semaphore definitions. + */ +struct sem { +#define SEM_MAGIC ((u_int32_t) 0x09fa4012) + u_int32_t magic; + pthread_mutex_t lock; + pthread_cond_t gtzero; + u_int32_t count; + u_int32_t nwaiters; +#define SEM_USER (NULL) + semid_t semid; /* semaphore id if kernel (shared) semaphore */ + int syssem; /* 1 if kernel (shared) semaphore */ + LIST_ENTRY(sem) entry; + struct sem **backpointer; +}; + +typedef struct sem* sem_t; + +#define SEM_FAILED ((sem_t *)0) +#define SEM_VALUE_MAX __INT_MAX + +#define SYM_FB10(sym) __CONCAT(sym, _fb10) +#define WEAK_REF(sym, alias) __weak_reference(sym, alias) +#define SYM_COMPAT(sym, impl, ver) __sym_compat(sym, impl, ver) + +#define FB10_COMPAT(func, sym) \ + WEAK_REF(func, SYM_FB10(sym)); \ + SYM_COMPAT(sym, SYM_FB10(sym), FBSD_1.0) + +static sem_t sem_alloc(unsigned int value, semid_t semid, int system_sem); +static void sem_free(sem_t sem); + +static LIST_HEAD(, sem) named_sems = LIST_HEAD_INITIALIZER(named_sems); +static pthread_mutex_t named_sems_mtx = PTHREAD_MUTEX_INITIALIZER; + +FB10_COMPAT(_libc_sem_init_compat, sem_init); +FB10_COMPAT(_libc_sem_destroy_compat, sem_destroy); +FB10_COMPAT(_libc_sem_open_compat, sem_open); +FB10_COMPAT(_libc_sem_close_compat, sem_close); +FB10_COMPAT(_libc_sem_unlink_compat, sem_unlink); +FB10_COMPAT(_libc_sem_wait_compat, sem_wait); +FB10_COMPAT(_libc_sem_trywait_compat, sem_trywait); +FB10_COMPAT(_libc_sem_timedwait_compat, sem_timedwait); +FB10_COMPAT(_libc_sem_post_compat, sem_post); +FB10_COMPAT(_libc_sem_getvalue_compat, sem_getvalue); + +static inline int +sem_check_validity(sem_t *sem) +{ + + if ((sem != NULL) && ((*sem)->magic == SEM_MAGIC)) + return (0); + else { + errno = EINVAL; + return (-1); + } +} + +static void +sem_free(sem_t sem) +{ + + sem->magic = 0; + free(sem); +} + +static sem_t +sem_alloc(unsigned int value, semid_t semid, int system_sem) +{ + sem_t sem; + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return (NULL); + } + + sem = (sem_t)malloc(sizeof(struct sem)); + if (sem == NULL) { + errno = ENOSPC; + return (NULL); + } + + sem->count = (u_int32_t)value; + sem->nwaiters = 0; + sem->magic = SEM_MAGIC; + sem->semid = semid; + sem->syssem = system_sem; + return (sem); +} + +int +_libc_sem_init_compat(sem_t *sem, int pshared, unsigned int value) +{ + semid_t semid; + + /* + * We always have to create the kernel semaphore if the + * threads library isn't present since libc's version of + * pthread_cond_wait() is just a stub that doesn't really + * wait. + */ + semid = (semid_t)SEM_USER; + if ((pshared != 0) && ksem_init(&semid, value) != 0) + return (-1); + + *sem = sem_alloc(value, semid, pshared); + if ((*sem) == NULL) { + if (pshared != 0) + ksem_destroy(semid); + return (-1); + } + return (0); +} + +int +_libc_sem_destroy_compat(sem_t *sem) +{ + int retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + /* + * If this is a system semaphore let the kernel track it otherwise + * make sure there are no waiters. + */ + if ((*sem)->syssem != 0) + retval = ksem_destroy((*sem)->semid); + else if ((*sem)->nwaiters > 0) { + errno = EBUSY; + retval = -1; + } + else { + retval = 0; + (*sem)->magic = 0; + } + + if (retval == 0) + sem_free(*sem); + return (retval); +} + +sem_t * +_libc_sem_open_compat(const char *name, int oflag, ...) +{ + sem_t *sem; + sem_t s; + semid_t semid; + mode_t mode; + unsigned int value; + + mode = 0; + value = 0; + + if ((oflag & O_CREAT) != 0) { + va_list ap; + + va_start(ap, oflag); + mode = va_arg(ap, int); + value = va_arg(ap, unsigned int); + va_end(ap); + } + /* + * we can be lazy and let the kernel handle the "oflag", + * we'll just merge duplicate IDs into our list. + */ + if (ksem_open(&semid, name, oflag, mode, value) == -1) + return (SEM_FAILED); + /* + * search for a duplicate ID, we must return the same sem_t * + * if we locate one. + */ + _pthread_mutex_lock(&named_sems_mtx); + LIST_FOREACH(s, &named_sems, entry) { + if (s->semid == semid) { + sem = s->backpointer; + _pthread_mutex_unlock(&named_sems_mtx); + return (sem); + } + } + sem = (sem_t *)malloc(sizeof(*sem)); + if (sem == NULL) + goto err; + *sem = sem_alloc(value, semid, 1); + if ((*sem) == NULL) + goto err; + LIST_INSERT_HEAD(&named_sems, *sem, entry); + (*sem)->backpointer = sem; + _pthread_mutex_unlock(&named_sems_mtx); + return (sem); +err: + _pthread_mutex_unlock(&named_sems_mtx); + ksem_close(semid); + if (sem != NULL) { + if (*sem != NULL) + sem_free(*sem); + else + errno = ENOSPC; + free(sem); + } else { + errno = ENOSPC; + } + return (SEM_FAILED); +} + +int +_libc_sem_close_compat(sem_t *sem) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem == 0) { + errno = EINVAL; + return (-1); + } + + _pthread_mutex_lock(&named_sems_mtx); + if (ksem_close((*sem)->semid) != 0) { + _pthread_mutex_unlock(&named_sems_mtx); + return (-1); + } + LIST_REMOVE((*sem), entry); + _pthread_mutex_unlock(&named_sems_mtx); + sem_free(*sem); + *sem = NULL; + free(sem); + return (0); +} + +int +_libc_sem_unlink_compat(const char *name) +{ + + return (ksem_unlink(name)); +} + +static int +_umtx_wait_uint(volatile unsigned *mtx, unsigned id, const struct timespec *abstime) +{ + struct _umtx_time *tm_p, timeout; + size_t tm_size; + + if (abstime == NULL) { + tm_p = NULL; + tm_size = 0; + } else { + timeout._clockid = CLOCK_REALTIME; + timeout._flags = UMTX_ABSTIME; + timeout._timeout = *abstime; + tm_p = &timeout; + tm_size = sizeof(timeout); + } + return _umtx_op(__DEVOLATILE(void *, mtx), + UMTX_OP_WAIT_UINT_PRIVATE, id, + (void *)tm_size, __DECONST(void*, tm_p)); +} + +static int +_umtx_wake(volatile void *mtx) +{ + return _umtx_op(__DEVOLATILE(void *, mtx), UMTX_OP_WAKE_PRIVATE, + 1, NULL, NULL); +} + +#define TIMESPEC_SUB(dst, src, val) \ + do { \ + (dst)->tv_sec = (src)->tv_sec - (val)->tv_sec; \ + (dst)->tv_nsec = (src)->tv_nsec - (val)->tv_nsec; \ + if ((dst)->tv_nsec < 0) { \ + (dst)->tv_sec--; \ + (dst)->tv_nsec += 1000000000; \ + } \ + } while (0) + + +static void +sem_cancel_handler(void *arg) +{ + sem_t *sem = arg; + + atomic_add_int(&(*sem)->nwaiters, -1); + if ((*sem)->nwaiters && (*sem)->count) + _umtx_wake(&(*sem)->count); +} + +int +_libc_sem_timedwait_compat(sem_t * __restrict sem, + const struct timespec * __restrict abstime) +{ + int val, retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem != 0) { + _pthread_cancel_enter(1); + retval = ksem_wait((*sem)->semid); /* XXX no timeout */ + _pthread_cancel_leave(retval == -1); + return (retval); + } + + retval = 0; + _pthread_testcancel(); + for (;;) { + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + if (retval) { + _pthread_testcancel(); + break; + } + if (abstime) { + if (abstime->tv_nsec >= 1000000000 || abstime->tv_nsec < 0) { + errno = EINVAL; + return (-1); + } + } + atomic_add_int(&(*sem)->nwaiters, 1); + pthread_cleanup_push(sem_cancel_handler, sem); + _pthread_cancel_enter(1); + retval = _umtx_wait_uint(&(*sem)->count, 0, abstime); + _pthread_cancel_leave(0); + pthread_cleanup_pop(0); + atomic_add_int(&(*sem)->nwaiters, -1); + } + return (retval); +} + +int +_libc_sem_wait_compat(sem_t *sem) +{ + return _libc_sem_timedwait_compat(sem, NULL); +} + +int +_libc_sem_trywait_compat(sem_t *sem) +{ + int val; + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem != 0) + return ksem_trywait((*sem)->semid); + + while ((val = (*sem)->count) > 0) { + if (atomic_cmpset_acq_int(&(*sem)->count, val, val - 1)) + return (0); + } + errno = EAGAIN; + return (-1); +} + +int +_libc_sem_post_compat(sem_t *sem) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem != 0) + return ksem_post((*sem)->semid); + + atomic_add_rel_int(&(*sem)->count, 1); + rmb(); + if ((*sem)->nwaiters) + return _umtx_wake(&(*sem)->count); + return (0); +} + +int +_libc_sem_getvalue_compat(sem_t * __restrict sem, int * __restrict sval) +{ + int retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + if ((*sem)->syssem != 0) + retval = ksem_getvalue((*sem)->semid, sval); + else { + *sval = (int)(*sem)->count; + retval = 0; + } + return (retval); +} diff --git a/lib/libc/gen/sem_destroy.3 b/lib/libc/gen/sem_destroy.3 new file mode 100644 index 000000000000..13cc81a03710 --- /dev/null +++ b/lib/libc/gen/sem_destroy.3 @@ -0,0 +1,85 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd February 15, 2000 +.Dt SEM_DESTROY 3 +.Os +.Sh NAME +.Nm sem_destroy +.Nd destroy an unnamed semaphore +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In semaphore.h +.Ft int +.Fn sem_destroy "sem_t *sem" +.Sh DESCRIPTION +The +.Fn sem_destroy +function destroys the unnamed semaphore pointed to by +.Fa sem . +After a successful call to +.Fn sem_destroy , +.Fa sem +is unusable until re-initialized by another call to +.Xr sem_init 3 . +.Sh RETURN VALUES +.Rv -std sem_destroy +.Sh ERRORS +The +.Fn sem_destroy +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sem +argument +points to an invalid semaphore. +.It Bq Er EBUSY +There are currently threads blocked on the semaphore that +.Fa sem +points to. +.El +.Sh SEE ALSO +.Xr sem_init 3 +.Sh STANDARDS +The +.Fn sem_destroy +function conforms to +.St -p1003.1-96 . +.Pp +.Tn POSIX +does not define the behavior of +.Fn sem_destroy +if called while there are threads blocked on +.Fa sem , +but this implementation is guaranteed to return \-1 and set +.Va errno +to +.Er EBUSY +if there are threads blocked on +.Fa sem . diff --git a/lib/libc/gen/sem_getvalue.3 b/lib/libc/gen/sem_getvalue.3 new file mode 100644 index 000000000000..8b2970373287 --- /dev/null +++ b/lib/libc/gen/sem_getvalue.3 @@ -0,0 +1,78 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd February 15, 2000 +.Dt SEM_GETVALUE 3 +.Os +.Sh NAME +.Nm sem_getvalue +.Nd get the value of a semaphore +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In semaphore.h +.Ft int +.Fn sem_getvalue "sem_t * restrict sem" "int * restrict sval" +.Sh DESCRIPTION +The +.Fn sem_getvalue +function sets the variable pointed to by +.Fa sval +to the current value of the semaphore pointed to by +.Fa sem , +as of the time that the call to +.Fn sem_getvalue +is actually run. +.Sh RETURN VALUES +.Rv -std sem_getvalue +.Sh ERRORS +The +.Fn sem_getvalue +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sem +argument +points to an invalid semaphore. +.El +.Sh SEE ALSO +.Xr sem_post 3 , +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +The +.Fn sem_getvalue +function conforms to +.St -p1003.1-96 . +.Pp +The value of the semaphore is never negative, even if there are threads blocked +on the semaphore. +.Tn POSIX +is somewhat ambiguous in its wording with regard to +what the value of the semaphore should be if there are blocked waiting threads, +but this behavior is conformant, given the wording of the specification. diff --git a/lib/libc/gen/sem_init.3 b/lib/libc/gen/sem_init.3 new file mode 100644 index 000000000000..e0e4b3b3d6c2 --- /dev/null +++ b/lib/libc/gen/sem_init.3 @@ -0,0 +1,99 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 9, 2010 +.Dt SEM_INIT 3 +.Os +.Sh NAME +.Nm sem_init +.Nd initialize an unnamed semaphore +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In semaphore.h +.Ft int +.Fn sem_init "sem_t *sem" "int pshared" "unsigned int value" +.Sh DESCRIPTION +The +.Fn sem_init +function initializes the unnamed semaphore pointed to by +.Fa sem +to have the value +.Fa value . +.Pp +A non-zero value for +.Fa pshared +specifies a shared semaphore that can be used by multiple processes, +the semaphore should be located in shared memory region (see +.Xr mmap 2 , +.Xr shm_open 2 , +and +.Xr shmget 2 ) , +any process having read and write access to address +.Fa sem +can perform semaphore operations on +.Fa sem . +.Pp +Following a successful call to +.Fn sem_init , +.Fa sem +can be used as an argument in subsequent calls to +.Xr sem_wait 3 , +.Xr sem_trywait 3 , +.Xr sem_post 3 , +and +.Xr sem_destroy 3 . +The +.Fa sem +argument is no longer valid after a successful call to +.Xr sem_destroy 3 . +.Sh RETURN VALUES +.Rv -std sem_init +.Sh ERRORS +The +.Fn sem_init +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa value +argument exceeds +.Dv SEM_VALUE_MAX . +.It Bq Er ENOSPC +Memory allocation error. +.El +.Sh SEE ALSO +.Xr sem_destroy 3 , +.Xr sem_getvalue 3 , +.Xr sem_post 3 , +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +The +.Fn sem_init +function conforms to +.St -p1003.1-96 . diff --git a/lib/libc/gen/sem_new.c b/lib/libc/gen/sem_new.c new file mode 100644 index 000000000000..ba81fb0ded78 --- /dev/null +++ b/lib/libc/gen/sem_new.c @@ -0,0 +1,470 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (C) 2010 David Xu <davidxu@freebsd.org>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/queue.h> +#include <sys/mman.h> +#include <sys/stat.h> +#include <errno.h> +#include <machine/atomic.h> +#include <sys/umtx.h> +#include <limits.h> +#include <fcntl.h> +#include <pthread.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <semaphore.h> +#include <unistd.h> +#include "un-namespace.h" +#include "libc_private.h" + +__weak_reference(_sem_close, sem_close); +__weak_reference(_sem_destroy, sem_destroy); +__weak_reference(_sem_getvalue, sem_getvalue); +__weak_reference(_sem_init, sem_init); +__weak_reference(_sem_open, sem_open); +__weak_reference(_sem_post, sem_post); +__weak_reference(_sem_timedwait, sem_timedwait); +__weak_reference(_sem_clockwait_np, sem_clockwait_np); +__weak_reference(_sem_trywait, sem_trywait); +__weak_reference(_sem_unlink, sem_unlink); +__weak_reference(_sem_wait, sem_wait); + +#define SEM_PREFIX "/tmp/SEMD" +#define SEM_MAGIC ((u_int32_t)0x73656d32) + +_Static_assert(SEM_VALUE_MAX <= USEM_MAX_COUNT, "SEM_VALUE_MAX too large"); + +struct sem_nameinfo { + int open_count; + char *name; + dev_t dev; + ino_t ino; + sem_t *sem; + LIST_ENTRY(sem_nameinfo) next; +}; + +static pthread_once_t once = PTHREAD_ONCE_INIT; +static pthread_mutex_t sem_llock; +static LIST_HEAD(, sem_nameinfo) sem_list = LIST_HEAD_INITIALIZER(sem_list); + +static void +sem_prefork(void) +{ + + _pthread_mutex_lock(&sem_llock); +} + +static void +sem_postfork(void) +{ + + _pthread_mutex_unlock(&sem_llock); +} + +static void +sem_child_postfork(void) +{ + + _pthread_mutex_unlock(&sem_llock); +} + +static void +sem_module_init(void) +{ + + _pthread_mutex_init(&sem_llock, NULL); + _pthread_atfork(sem_prefork, sem_postfork, sem_child_postfork); +} + +static inline int +sem_check_validity(sem_t *sem) +{ + + if (sem->_magic == SEM_MAGIC) + return (0); + errno = EINVAL; + return (-1); +} + +int +_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + return (-1); + } + + bzero(sem, sizeof(sem_t)); + sem->_magic = SEM_MAGIC; + sem->_kern._count = (u_int32_t)value; + sem->_kern._flags = pshared ? USYNC_PROCESS_SHARED : 0; + return (0); +} + +sem_t * +_sem_open(const char *name, int flags, ...) +{ + char path[PATH_MAX]; + struct stat sb; + va_list ap; + struct sem_nameinfo *ni; + sem_t *sem, tmp; + int errsave, fd, len, mode, value; + + ni = NULL; + sem = NULL; + fd = -1; + value = 0; + + if (name[0] != '/') { + errno = EINVAL; + return (SEM_FAILED); + } + name++; + strcpy(path, SEM_PREFIX); + if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { + errno = ENAMETOOLONG; + return (SEM_FAILED); + } + if (flags & ~(O_CREAT|O_EXCL)) { + errno = EINVAL; + return (SEM_FAILED); + } + if ((flags & O_CREAT) != 0) { + va_start(ap, flags); + mode = va_arg(ap, int); + value = va_arg(ap, int); + va_end(ap); + } + fd = -1; + _pthread_once(&once, sem_module_init); + + _pthread_mutex_lock(&sem_llock); + LIST_FOREACH(ni, &sem_list, next) { + if (ni->name != NULL && strcmp(name, ni->name) == 0) { + fd = _open(path, flags | O_RDWR | O_CLOEXEC | + O_EXLOCK, mode); + if (fd == -1 || _fstat(fd, &sb) == -1) { + ni = NULL; + goto error; + } + if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | + O_EXCL) || ni->dev != sb.st_dev || + ni->ino != sb.st_ino) { + ni->name = NULL; + ni = NULL; + break; + } + ni->open_count++; + sem = ni->sem; + _pthread_mutex_unlock(&sem_llock); + _close(fd); + return (sem); + } + } + + len = sizeof(*ni) + strlen(name) + 1; + ni = (struct sem_nameinfo *)malloc(len); + if (ni == NULL) { + errno = ENOSPC; + goto error; + } + + ni->name = (char *)(ni+1); + strcpy(ni->name, name); + + if (fd == -1) { + fd = _open(path, flags | O_RDWR | O_CLOEXEC | O_EXLOCK, mode); + if (fd == -1 || _fstat(fd, &sb) == -1) + goto error; + } + if (sb.st_size < sizeof(sem_t)) { + tmp._magic = SEM_MAGIC; + tmp._kern._count = value; + tmp._kern._flags = USYNC_PROCESS_SHARED | SEM_NAMED; + if (_write(fd, &tmp, sizeof(tmp)) != sizeof(tmp)) + goto error; + } + flock(fd, LOCK_UN); + sem = mmap(NULL, sizeof(sem_t), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_NOSYNC, fd, 0); + if (sem == MAP_FAILED) { + sem = NULL; + if (errno == ENOMEM) + errno = ENOSPC; + goto error; + } + if (sem->_magic != SEM_MAGIC) { + errno = EINVAL; + goto error; + } + ni->open_count = 1; + ni->sem = sem; + ni->dev = sb.st_dev; + ni->ino = sb.st_ino; + LIST_INSERT_HEAD(&sem_list, ni, next); + _close(fd); + _pthread_mutex_unlock(&sem_llock); + return (sem); + +error: + errsave = errno; + if (fd != -1) + _close(fd); + if (sem != NULL) + munmap(sem, sizeof(sem_t)); + free(ni); + _pthread_mutex_unlock(&sem_llock); + errno = errsave; + return (SEM_FAILED); +} + +int +_sem_close(sem_t *sem) +{ + struct sem_nameinfo *ni; + bool last; + + if (sem_check_validity(sem) != 0) + return (-1); + + if (!(sem->_kern._flags & SEM_NAMED)) { + errno = EINVAL; + return (-1); + } + + _pthread_once(&once, sem_module_init); + + _pthread_mutex_lock(&sem_llock); + LIST_FOREACH(ni, &sem_list, next) { + if (sem == ni->sem) { + last = --ni->open_count == 0; + if (last) + LIST_REMOVE(ni, next); + _pthread_mutex_unlock(&sem_llock); + if (last) { + munmap(sem, sizeof(*sem)); + free(ni); + } + return (0); + } + } + _pthread_mutex_unlock(&sem_llock); + errno = EINVAL; + return (-1); +} + +int +_sem_unlink(const char *name) +{ + char path[PATH_MAX]; + + if (name[0] != '/') { + errno = ENOENT; + return -1; + } + name++; + strcpy(path, SEM_PREFIX); + if (strlcat(path, name, sizeof(path)) >= sizeof(path)) { + errno = ENAMETOOLONG; + return (-1); + } + + return (unlink(path)); +} + +int +_sem_destroy(sem_t *sem) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + if (sem->_kern._flags & SEM_NAMED) { + errno = EINVAL; + return (-1); + } + sem->_magic = 0; + return (0); +} + +int +_sem_getvalue(sem_t * __restrict sem, int * __restrict sval) +{ + + if (sem_check_validity(sem) != 0) + return (-1); + + *sval = (int)USEM_COUNT(sem->_kern._count); + return (0); +} + +static __inline int +usem_wake(struct _usem2 *sem) +{ + + return (_umtx_op(sem, UMTX_OP_SEM2_WAKE, 0, NULL, NULL)); +} + +static __inline int +usem_wait(struct _usem2 *sem, clockid_t clock_id, int flags, + const struct timespec *rqtp, struct timespec *rmtp) +{ + struct { + struct _umtx_time timeout; + struct timespec remain; + } tms; + void *tm_p; + size_t tm_size; + int retval; + + if (rqtp == NULL) { + tm_p = NULL; + tm_size = 0; + } else { + tms.timeout._clockid = clock_id; + tms.timeout._flags = (flags & TIMER_ABSTIME) ? UMTX_ABSTIME : 0; + tms.timeout._timeout = *rqtp; + tm_p = &tms; + tm_size = sizeof(tms); + } + retval = _umtx_op(sem, UMTX_OP_SEM2_WAIT, 0, (void *)tm_size, tm_p); + if (retval == -1 && errno == EINTR && (flags & TIMER_ABSTIME) == 0 && + rqtp != NULL && rmtp != NULL) { + *rmtp = tms.remain; + } + + return (retval); +} + +int +_sem_trywait(sem_t *sem) +{ + int val; + + if (sem_check_validity(sem) != 0) + return (-1); + + while (USEM_COUNT(val = sem->_kern._count) > 0) { + if (atomic_cmpset_acq_int(&sem->_kern._count, val, val - 1)) + return (0); + } + errno = EAGAIN; + return (-1); +} + +int +_sem_clockwait_np(sem_t * __restrict sem, clockid_t clock_id, int flags, + const struct timespec *rqtp, struct timespec *rmtp) +{ + int val, retval; + + if (sem_check_validity(sem) != 0) + return (-1); + + retval = 0; + _pthread_testcancel(); + for (;;) { + while (USEM_COUNT(val = sem->_kern._count) > 0) { + if (atomic_cmpset_acq_int(&sem->_kern._count, val, + val - 1)) + return (0); + } + + if (retval) { + _pthread_testcancel(); + break; + } + + /* + * The timeout argument is only supposed to + * be checked if the thread would have blocked. + */ + if (rqtp != NULL) { + if (rqtp->tv_nsec >= 1000000000 || rqtp->tv_nsec < 0) { + errno = EINVAL; + return (-1); + } + } + _pthread_cancel_enter(1); + retval = usem_wait(&sem->_kern, clock_id, flags, rqtp, rmtp); + _pthread_cancel_leave(0); + } + return (retval); +} + +int +_sem_timedwait(sem_t * __restrict sem, + const struct timespec * __restrict abstime) +{ + + return (_sem_clockwait_np(sem, CLOCK_REALTIME, TIMER_ABSTIME, abstime, + NULL)); +}; + +int +_sem_wait(sem_t *sem) +{ + + return (_sem_timedwait(sem, NULL)); +} + +/* + * POSIX: + * The sem_post() interface is reentrant with respect to signals and may be + * invoked from a signal-catching function. + * The implementation does not use lock, so it should be safe. + */ +int +_sem_post(sem_t *sem) +{ + unsigned int count; + + if (sem_check_validity(sem) != 0) + return (-1); + + do { + count = sem->_kern._count; + if (USEM_COUNT(count) + 1 > SEM_VALUE_MAX) { + errno = EOVERFLOW; + return (-1); + } + } while (!atomic_cmpset_rel_int(&sem->_kern._count, count, count + 1)); + if (count & USEM_HAS_WAITERS) + usem_wake(&sem->_kern); + return (0); +} diff --git a/lib/libc/gen/sem_open.3 b/lib/libc/gen/sem_open.3 new file mode 100644 index 000000000000..76fa3463e1ab --- /dev/null +++ b/lib/libc/gen/sem_open.3 @@ -0,0 +1,222 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 9, 2010 +.Dt SEM_OPEN 3 +.Os +.Sh NAME +.Nm sem_open , +.Nm sem_close , +.Nm sem_unlink +.Nd named semaphore operations +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In semaphore.h +.Ft "sem_t *" +.Fn sem_open "const char *name" "int oflag" ... +.Ft int +.Fn sem_close "sem_t *sem" +.Ft int +.Fn sem_unlink "const char *name" +.Sh DESCRIPTION +The +.Fn sem_open +function creates or opens the named semaphore specified by +.Fa name . +The returned semaphore may be used in subsequent calls to +.Xr sem_getvalue 3 , +.Xr sem_wait 3 , +.Xr sem_trywait 3 , +.Xr sem_post 3 , +and +.Fn sem_close . +.Pp +This implementation places strict requirements on the value of +.Fa name : +it must begin with a slash +.Pq Ql / +and contain no other slash characters. +.Pp +The following bits may be set in the +.Fa oflag +argument: +.Bl -tag -width ".Dv O_CREAT" +.It Dv O_CREAT +Create the semaphore if it does not already exist. +.Pp +The third argument to the call to +.Fn sem_open +must be of type +.Vt mode_t +and specifies the mode for the semaphore. +Only the +.Dv S_IWUSR , S_IWGRP , +and +.Dv S_IWOTH +bits are examined; +it is not possible to grant only +.Dq read +permission on a semaphore. +The mode is modified according to the process's file creation +mask; see +.Xr umask 2 . +.Pp +The fourth argument must be an +.Vt "unsigned int" +and specifies the initial value for the semaphore, +and must be no greater than +.Dv SEM_VALUE_MAX . +.It Dv O_EXCL +Create the semaphore if it does not exist. +If the semaphore already exists, +.Fn sem_open +will fail. +This flag is ignored unless +.Dv O_CREAT +is also specified. +.El +.Pp +The +.Fn sem_close +function closes a named semaphore that was opened by a call to +.Fn sem_open . +.Pp +The +.Fn sem_unlink +function removes the semaphore named +.Fa name . +Resources allocated to the semaphore are only deallocated when all +processes that have the semaphore open close it. +.Sh RETURN VALUES +If successful, +the +.Fn sem_open +function returns the address of the opened semaphore. +If the same +.Fa name +argument is given to multiple calls to +.Fn sem_open +by the same process without an intervening call to +.Fn sem_close , +the same address is returned each time. +If the semaphore cannot be opened, +.Fn sem_open +returns +.Dv SEM_FAILED +and the global variable +.Va errno +is set to indicate the error. +.Pp +.Rv -std sem_close sem_unlink +.Sh ERRORS +The +.Fn sem_open +function will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +The semaphore exists and the permissions specified by +.Fa oflag +at the time it was created deny access to this process. +.It Bq Er EACCES +The semaphore does not exist, but permission to create it is denied. +.It Bq Er EEXIST +.Dv O_CREAT +and +.Dv O_EXCL +are set but the semaphore already exists. +.It Bq Er EINTR +The call was interrupted by a signal. +.It Bq Er EINVAL +The +.Fn sem_open +operation is not supported for the given +.Fa name . +.It Bq Er EINVAL +The +.Fa value +argument is greater than +.Dv SEM_VALUE_MAX . +.\"FreeBSD never returns EMFILE +.\".It Bq Er EMFILE +.\"Too many semaphores are in use by this process. +.It Bq Er ENAMETOOLONG +The +.Fa name +argument is too long. +.It Bq Er ENFILE +The system limit on semaphores has been reached. +.It Bq Er ENOENT +.Dv O_CREAT +is not set but the named semaphore does not exist. +.It Bq Er ENOSPC +There is not enough space to create the semaphore. +.El +.Pp +The +.Fn sem_close +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sem +argument is not a valid semaphore. +.El +.Pp +The +.Fn sem_unlink +function will fail if: +.Bl -tag -width Er +.It Bq Er EACCES +Permission is denied to unlink the semaphore. +.It Bq Er ENAMETOOLONG +The specified +.Fa name +is too long. +.It Bq Er ENOENT +The named semaphore does not exist. +.El +.Sh SEE ALSO +.Xr close 2 , +.Xr open 2 , +.Xr umask 2 , +.Xr unlink 2 , +.Xr sem_getvalue 3 , +.Xr sem_post 3 , +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +The +.Fn sem_open , +.Fn sem_close , +and +.Fn sem_unlink +functions conform to +.St -p1003.1-96 . +.Sh HISTORY +Support for named semaphores first appeared in +.Fx 5.0 . diff --git a/lib/libc/gen/sem_post.3 b/lib/libc/gen/sem_post.3 new file mode 100644 index 000000000000..b389b6686a20 --- /dev/null +++ b/lib/libc/gen/sem_post.3 @@ -0,0 +1,78 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd January 28, 2015 +.Dt SEM_POST 3 +.Os +.Sh NAME +.Nm sem_post +.Nd increment (unlock) a semaphore +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In semaphore.h +.Ft int +.Fn sem_post "sem_t *sem" +.Sh DESCRIPTION +The +.Fn sem_post +function increments (unlocks) the semaphore pointed to by +.Fa sem . +If there are threads blocked on the semaphore when +.Fn sem_post +is called, then the highest priority thread that has been blocked the longest on +the semaphore will be allowed to return from +.Fn sem_wait . +.Pp +The +.Fn sem_post +function is signal-reentrant and may be called within signal handlers. +.Sh RETURN VALUES +.Rv -std sem_post +.Sh ERRORS +The +.Fn sem_post +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sem +argument +points to an invalid semaphore. +.It Bq Er EOVERFLOW +The semaphore value would exceed +.Dv SEM_VALUE_MAX . +.El +.Sh SEE ALSO +.Xr sem_getvalue 3 , +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +The +.Fn sem_post +function conforms to +.St -p1003.1-96 . diff --git a/lib/libc/gen/sem_timedwait.3 b/lib/libc/gen/sem_timedwait.3 new file mode 100644 index 000000000000..8f253bb35f72 --- /dev/null +++ b/lib/libc/gen/sem_timedwait.3 @@ -0,0 +1,161 @@ +.\" Copyright (c) 2008, David Xu <davidxu@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd May 24, 2017 +.Dt SEM_TIMEDWAIT 3 +.Os +.Sh NAME +.Nm sem_timedwait , +.Nm sem_clockwait_np +.Nd "lock a semaphore" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In semaphore.h +.In time.h +.Ft int +.Fn sem_timedwait "sem_t * restrict sem" "const struct timespec * restrict abs_timeout" +.Ft int +.Fn sem_clockwait_np "sem_t * restrict sem" "clockid_t clock_id" "int flags" "const struct timespec * rqtp" "struct timespec * rmtp" +.Sh DESCRIPTION +The +.Fn sem_timedwait +function locks the semaphore referenced by +.Fa sem , +as in the +.Xr sem_wait 3 +function. +However, if the semaphore cannot be locked without waiting for +another process or thread to unlock the semaphore by performing +a +.Xr sem_post 3 +function, this wait will be terminated when the specified timeout expires. +.Pp +The timeout will expire when the absolute time specified by +.Fa abs_timeout +passes, as measured by the clock on which timeouts are based (that is, +when the value of that clock equals or exceeds +.Fa abs_timeout ) , +or if the +absolute time specified by +.Fa abs_timeout +has already been passed at the time of the call. +.Pp +Note that the timeout is based on the +.Dv CLOCK_REALTIME +clock. +.Pp +The validity of the +.Fa abs_timeout +is not checked if the semaphore can be locked immediately. +.Pp +The +.Fn sem_clockwait_np +function is a more flexible variant of +.Fn sem_timedwait . +The +.Fa clock_id +parameter specifies the reference clock. +If the +.Fa flags +parameter contains +.Dv TIMER_ABSTIME , +then the requested timeout +.Pq Fa rqtp +is an absolute timeout; otherwise, +the timeout is relative. +If this function fails with +.Er EINTR +and the timeout is relative, +a non-NULL +.Fa rmtp +will be updated to contain the amount of time remaining in the interval +.Po +the requested time minus the time actually slept +.Pc . +An absolute timeout has no effect on +.Fa rmtp . +A single structure can be used for both +.Fa rqtp +and +.Fa rmtp . +.Sh RETURN VALUES +These +functions return zero if the calling process successfully performed the +semaphore lock operation on the semaphore designated by +.Fa sem . +If the call was unsuccessful, the state of the semaphore is unchanged, +and the function returns a value of \-1 and sets the global variable +.Va errno +to indicate the error. +.Sh ERRORS +These functions will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sem +argument does not refer to a valid semaphore, or the process or thread would +have blocked, and the +.Fa abs_timeout +parameter specified a nanoseconds field value less than zero or greater than +or equal to 1000 million. +.It Bq Er ETIMEDOUT +The semaphore could not be locked before the specified timeout expired. +.It Bq Er EINTR +A signal interrupted this function. +.El +.Sh SEE ALSO +.Xr sem_post 3 , +.Xr sem_trywait 3 , +.Xr sem_wait 3 +.Sh STANDARDS +The +.Fn sem_timedwait +function conforms to +.St -p1003.1-2004 . +The +.Fn sem_clockwait_np +function is not specified by any standard; +it exists only on +.Fx +at the time of this writing. +.Sh HISTORY +The +.Fn sem_timedwait +function first appeared in +.Fx 5.0 . +The +.Fn sem_clockwait_np +function first appeared in +.Fx 11.1 . diff --git a/lib/libc/gen/sem_wait.3 b/lib/libc/gen/sem_wait.3 new file mode 100644 index 000000000000..2d4c77829a95 --- /dev/null +++ b/lib/libc/gen/sem_wait.3 @@ -0,0 +1,100 @@ +.\" Copyright (C) 2000 Jason Evans <jasone@FreeBSD.org>. +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice(s), this list of conditions and the following disclaimer as +.\" the first lines of this file unmodified other than the possible +.\" addition of one or more copyright notices. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice(s), this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd April 16, 2013 +.Dt SEM_WAIT 3 +.Os +.Sh NAME +.Nm sem_wait , +.Nm sem_trywait +.Nd decrement (lock) a semaphore +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In semaphore.h +.Ft int +.Fn sem_wait "sem_t *sem" +.Ft int +.Fn sem_trywait "sem_t *sem" +.Sh DESCRIPTION +The +.Fn sem_wait +function decrements (locks) the semaphore pointed to by +.Fa sem , +but blocks if the value of +.Fa sem +is zero, until the value is non-zero and the value can be decremented. +.Pp +The +.Fn sem_trywait +function decrements (locks) the semaphore pointed to by +.Fa sem +only if the value is non-zero. +Otherwise, the semaphore is not decremented and +an error is returned. +.Sh RETURN VALUES +.Rv -std +.Sh ERRORS +The +.Fn sem_wait +and +.Fn sem_trywait +functions will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sem +argument +points to an invalid semaphore. +.El +.Pp +Additionally, +.Fn sem_wait +will fail if: +.Bl -tag -width Er +.It Bq Er EINTR +A signal interrupted this function. +.El +.Pp +Additionally, +.Fn sem_trywait +will fail if: +.Bl -tag -width Er +.It Bq Er EAGAIN +The semaphore value was zero, and thus could not be decremented. +.El +.Sh SEE ALSO +.Xr sem_getvalue 3 , +.Xr sem_post 3 , +.Xr sem_timedwait 3 +.Sh STANDARDS +The +.Fn sem_wait +and +.Fn sem_trywait +functions conform to +.St -p1003.1-96 . diff --git a/lib/libc/gen/semctl.c b/lib/libc/gen/semctl.c new file mode 100644 index 000000000000..374f01508236 --- /dev/null +++ b/lib/libc/gen/semctl.c @@ -0,0 +1,90 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2002 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + +#ifndef NO_COMPAT7 +#define _WANT_SEMUN_OLD +#endif +#define _WANT_SEMUN + +#include <sys/types.h> +#include <sys/ipc.h> +#include <sys/sem.h> +#include <stdarg.h> +#include <stdlib.h> + +int __semctl(int semid, int semnum, int cmd, union semun *arg); +#ifndef NO_COMPAT7 +int freebsd7___semctl(int semid, int semnum, int cmd, union semun_old *arg); +int freebsd7_semctl(int semid, int semnum, int cmd, ...); +#endif + +int +semctl(int semid, int semnum, int cmd, ...) +{ + va_list ap; + union semun semun; + union semun *semun_ptr; + + va_start(ap, cmd); + if (cmd == IPC_SET || cmd == IPC_STAT || cmd == GETALL + || cmd == SETVAL || cmd == SETALL) { + semun = va_arg(ap, union semun); + semun_ptr = &semun; + } else { + semun_ptr = NULL; + } + va_end(ap); + + return (__semctl(semid, semnum, cmd, semun_ptr)); +} + +#ifndef NO_COMPAT7 +int +freebsd7_semctl(int semid, int semnum, int cmd, ...) +{ + va_list ap; + union semun_old semun; + union semun_old *semun_ptr; + + va_start(ap, cmd); + if (cmd == IPC_SET || cmd == IPC_STAT || cmd == GETALL + || cmd == SETVAL || cmd == SETALL) { + semun = va_arg(ap, union semun_old); + semun_ptr = &semun; + } else { + semun_ptr = NULL; + } + va_end(ap); + + return (freebsd7___semctl(semid, semnum, cmd, semun_ptr)); +} + +__sym_compat(semctl, freebsd7_semctl, FBSD_1.0); +#endif diff --git a/lib/libc/gen/setdomainname.c b/lib/libc/gen/setdomainname.c new file mode 100644 index 000000000000..c40b7a393e3b --- /dev/null +++ b/lib/libc/gen/setdomainname.c @@ -0,0 +1,47 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <unistd.h> + +int +setdomainname(const char *name, int namelen) +{ + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_NISDOMAINNAME; + if (sysctl(mib, 2, NULL, NULL, (void *)name, namelen) == -1) + return (-1); + return (0); +} diff --git a/lib/libc/gen/sethostname.c b/lib/libc/gen/sethostname.c new file mode 100644 index 000000000000..eeb3ec5cc6db --- /dev/null +++ b/lib/libc/gen/sethostname.c @@ -0,0 +1,47 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <unistd.h> + +int +sethostname(const char *name, int namelen) +{ + int mib[2]; + + mib[0] = CTL_KERN; + mib[1] = KERN_HOSTNAME; + if (sysctl(mib, 2, NULL, NULL, (void *)name, namelen) == -1) + return (-1); + return (0); +} diff --git a/lib/libc/gen/setjmp.3 b/lib/libc/gen/setjmp.3 new file mode 100644 index 000000000000..e7c52473dbc9 --- /dev/null +++ b/lib/libc/gen/setjmp.3 @@ -0,0 +1,175 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 2, 2022 +.Dt SETJMP 3 +.Os +.Sh NAME +.Nm sigsetjmp , +.Nm siglongjmp , +.Nm setjmp , +.Nm longjmp , +.Nm _setjmp , +.Nm _longjmp , +.Nm longjmperror +.Nd non-local jumps +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In setjmp.h +.Ft int +.Fn sigsetjmp "sigjmp_buf env" "int savemask" +.Ft void +.Fn siglongjmp "sigjmp_buf env" "int val" +.Ft int +.Fn setjmp "jmp_buf env" +.Ft void +.Fn longjmp "jmp_buf env" "int val" +.Ft int +.Fn _setjmp "jmp_buf env" +.Ft void +.Fn _longjmp "jmp_buf env" "int val" +.Ft void +.Fn longjmperror void +.Sh DESCRIPTION +The +.Fn sigsetjmp , +.Fn setjmp , +and +.Fn _setjmp +functions save their calling environment in +.Fa env . +Each of these functions returns 0. +.Pp +The corresponding +.Fn longjmp +functions restore the environment saved by their most recent respective +invocations +of the +.Fn setjmp +function. +They then return so that program execution continues as if the corresponding +invocation of the +.Fn setjmp +call had just returned the value specified by +.Fa val , +instead of 0. +.Pp +Pairs of calls may be intermixed, i.e., both +.Fn sigsetjmp +and +.Fn siglongjmp +and +.Fn setjmp +and +.Fn longjmp +combinations may be used in the same program, however, individual +calls may not, e.g.\& the +.Fa env +argument to +.Fn setjmp +may not be passed to +.Fn siglongjmp . +.Pp +The +.Fn longjmp +routines may not be called after the routine which called the +.Fn setjmp +routines returns. +.Pp +All accessible objects have values as of the time +.Fn longjmp +routine was called, except that the values of objects of automatic storage +invocation duration that do not have the +.Vt volatile +type and have been changed between the +.Fn setjmp +invocation and +.Fn longjmp +call are indeterminate. +.Pp +The +.Fn setjmp Ns / Ns Fn longjmp +pairs save and restore the signal mask while +.Fn _setjmp Ns / Ns Fn _longjmp +pairs save and restore only the register set and the stack. +(See +.Fn sigprocmask 2 . ) +.Pp +The +.Fn sigsetjmp Ns / Ns Fn siglongjmp +function +pairs save and restore the signal mask if the argument +.Fa savemask +is non-zero, otherwise only the register set and the stack are saved. +.Sh ERRORS +If the contents of the +.Fa env +are corrupted, or correspond to an environment that has already returned, +the +.Fn longjmp +routine calls the routine +.Fn longjmperror 3 . +If +.Fn longjmperror +returns the program is aborted (see +.Xr abort 3 ) . +The default version of +.Fn longjmperror +prints the message +.Dq Li longjmp botch +to standard error and returns. +User programs wishing to exit more gracefully should write their own +versions of +.Fn longjmperror . +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr sigaltstack 2 , +.Xr signal 3 +.Sh STANDARDS +The +.Fn setjmp +and +.Fn longjmp +functions conform to +.St -isoC . +The +.Fn sigsetjmp +and +.Fn siglongjmp +functions conform to +.St -p1003.1-88 . +.Sh HISTORY +The +.Fn setjmp +and +.Fn longjmp +functions first appeared in the Programmer's Workbench (PWB/UNIX). diff --git a/lib/libc/gen/setjmperr.c b/lib/libc/gen/setjmperr.c new file mode 100644 index 000000000000..1ba722c30146 --- /dev/null +++ b/lib/libc/gen/setjmperr.c @@ -0,0 +1,49 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * This routine is called from longjmp() when an error occurs. + * Programs that wish to exit gracefully from this error may + * write their own versions. + * If this routine returns, the program is aborted. + */ + +#include "namespace.h" +#include <setjmp.h> +#include <unistd.h> +#include "un-namespace.h" + +void +longjmperror(void) +{ +#define ERRMSG "longjmp botch.\n" + (void)_write(STDERR_FILENO, ERRMSG, sizeof(ERRMSG) - 1); +} diff --git a/lib/libc/gen/setmode.3 b/lib/libc/gen/setmode.3 new file mode 100644 index 000000000000..a5dd05a5e7c6 --- /dev/null +++ b/lib/libc/gen/setmode.3 @@ -0,0 +1,131 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 18, 2019 +.Dt SETMODE 3 +.Os +.Sh NAME +.Nm getmode , +.Nm setmode +.Nd modify mode bits +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft mode_t +.Fn getmode "const void *set" "mode_t mode" +.Ft void * +.Fn setmode "const char *mode_str" +.Sh DESCRIPTION +The +.Fn getmode +function +returns a copy of the file permission bits +.Fa mode +as altered by the values pointed to by +.Fa set . +While only the mode bits are altered, other parts of the file mode +may be examined. +.Pp +The +.Fn setmode +function +takes an absolute (octal) or symbolic value, as described in +.Xr chmod 1 , +as an argument +and returns a pointer to mode values to be supplied to +.Fn getmode . +Because some of the symbolic values are relative to the file +creation mask, +.Fn setmode +may call +.Xr umask 2 . +If this occurs, the file creation mask will be restored before +.Fn setmode +returns. +If the calling program changes the value of its file creation mask +after calling +.Fn setmode , +.Fn setmode +must be called again if +.Fn getmode +is to modify future file modes correctly. +.Pp +If the mode passed to +.Fn setmode +is invalid or if memory cannot be allocated for the return value, +.Fn setmode +returns +.Dv NULL . +.Pp +The value returned from +.Fn setmode +is obtained from +.Fn malloc +and should be returned to the system with +.Fn free +when the program is done with it, generally after a call to +.Fn getmode . +.Sh ERRORS +The +.Fn setmode +function +may fail and set errno for any of the errors specified for the library +routine +.Xr malloc 3 +or +.Xr strtol 3 . +In addition, +.Fn setmode +will fail and set +.Va errno +to: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa mode +argument does not represent a valid mode. +.El +.Sh SEE ALSO +.Xr chmod 1 , +.Xr stat 2 , +.Xr umask 2 , +.Xr malloc 3 +.Sh HISTORY +The +.Fn getmode +and +.Fn setmode +functions first appeared in +.Bx 4.4 . +.Sh BUGS +The +.Fn setmode +function is not thread safe. +Files created in other threads while +.Fn setmode +is being called may be created with a umask of 0. diff --git a/lib/libc/gen/setmode.c b/lib/libc/gen/setmode.c new file mode 100644 index 000000000000..8d7ba905067f --- /dev/null +++ b/lib/libc/gen/setmode.c @@ -0,0 +1,482 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Dave Borman at Cray Research, Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/sysctl.h> + +#include <ctype.h> +#include <errno.h> +#include <limits.h> +#include <signal.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> + +#ifdef SETMODE_DEBUG +#include <stdio.h> +#endif +#include "un-namespace.h" +#include "libc_private.h" + +#define SET_LEN 6 /* initial # of bitcmd struct to malloc */ +#define SET_LEN_INCR 4 /* # of bitcmd structs to add as needed */ + +typedef struct bitcmd { + char cmd; + char cmd2; + mode_t bits; +} BITCMD; + +#define CMD2_CLR 0x01 +#define CMD2_SET 0x02 +#define CMD2_GBITS 0x04 +#define CMD2_OBITS 0x08 +#define CMD2_UBITS 0x10 + +static mode_t get_current_umask(void); +static BITCMD *addcmd(BITCMD *, mode_t, mode_t, mode_t, mode_t); +static void compress_mode(BITCMD *); +#ifdef SETMODE_DEBUG +static void dumpmode(BITCMD *); +#endif + +/* + * Given the old mode and an array of bitcmd structures, apply the operations + * described in the bitcmd structures to the old mode, and return the new mode. + * Note that there is no '=' command; a strict assignment is just a '-' (clear + * bits) followed by a '+' (set bits). + */ +mode_t +getmode(const void *bbox, mode_t omode) +{ + const BITCMD *set; + mode_t clrval, newmode, value; + + set = (const BITCMD *)bbox; + newmode = omode; + for (value = 0;; set++) + switch(set->cmd) { + /* + * When copying the user, group or other bits around, we "know" + * where the bits are in the mode so that we can do shifts to + * copy them around. If we don't use shifts, it gets real + * grundgy with lots of single bit checks and bit sets. + */ + case 'u': + value = (newmode & S_IRWXU) >> 6; + goto common; + + case 'g': + value = (newmode & S_IRWXG) >> 3; + goto common; + + case 'o': + value = newmode & S_IRWXO; +common: if (set->cmd2 & CMD2_CLR) { + clrval = + (set->cmd2 & CMD2_SET) ? S_IRWXO : value; + if (set->cmd2 & CMD2_UBITS) + newmode &= ~((clrval<<6) & set->bits); + if (set->cmd2 & CMD2_GBITS) + newmode &= ~((clrval<<3) & set->bits); + if (set->cmd2 & CMD2_OBITS) + newmode &= ~(clrval & set->bits); + } + if (set->cmd2 & CMD2_SET) { + if (set->cmd2 & CMD2_UBITS) + newmode |= (value<<6) & set->bits; + if (set->cmd2 & CMD2_GBITS) + newmode |= (value<<3) & set->bits; + if (set->cmd2 & CMD2_OBITS) + newmode |= value & set->bits; + } + break; + + case '+': + newmode |= set->bits; + break; + + case '-': + newmode &= ~set->bits; + break; + + case 'X': + if (omode & (S_IFDIR|S_IXUSR|S_IXGRP|S_IXOTH)) + newmode |= set->bits; + break; + + case '\0': + default: +#ifdef SETMODE_DEBUG + (void)printf("getmode:%04o -> %04o\n", omode, newmode); +#endif + return (newmode); + } +} + +#define ADDCMD(a, b, c, d) \ + if (set >= endset) { \ + BITCMD *newset; \ + setlen += SET_LEN_INCR; \ + newset = reallocarray(saveset, setlen, sizeof(BITCMD)); \ + if (newset == NULL) \ + goto out; \ + set = newset + (set - saveset); \ + saveset = newset; \ + endset = newset + (setlen - 2); \ + } \ + set = addcmd(set, (mode_t)(a), (mode_t)(b), (mode_t)(c), (d)) + +#define STANDARD_BITS (S_ISUID|S_ISGID|S_IRWXU|S_IRWXG|S_IRWXO) + +void * +setmode(const char *p) +{ + int serrno; + char op, *ep; + BITCMD *set, *saveset, *endset; + mode_t mask, perm, permXbits, who; + long perml; + int equalopdone; + u_int setlen; + + if (!*p) { + errno = EINVAL; + return (NULL); + } + + /* + * Get a copy of the mask for the permissions that are mask relative. + * Flip the bits, we want what's not set. + */ + mask = ~get_current_umask(); + + setlen = SET_LEN + 2; + + if ((set = malloc(setlen * sizeof(BITCMD))) == NULL) + return (NULL); + saveset = set; + endset = set + (setlen - 2); + + /* + * If an absolute number, get it and return; disallow non-octal digits + * or illegal bits. + */ + if (isdigit((unsigned char)*p)) { + errno = 0; + perml = strtol(p, &ep, 8); + if (*ep) { + errno = EINVAL; + goto out; + } + if (errno == ERANGE && (perml == LONG_MAX || perml == LONG_MIN)) + goto out; + if (perml & ~(STANDARD_BITS|S_ISTXT)) { + errno = EINVAL; + goto out; + } + perm = (mode_t)perml; + ADDCMD('=', (STANDARD_BITS|S_ISTXT), perm, mask); + set->cmd = 0; + return (saveset); + } + + /* + * Build list of structures to set/clear/copy bits as described by + * each clause of the symbolic mode. + */ + equalopdone = 0; + for (;;) { + /* First, find out which bits might be modified. */ + for (who = 0;; ++p) { + switch (*p) { + case 'a': + who |= STANDARD_BITS; + break; + case 'u': + who |= S_ISUID|S_IRWXU; + break; + case 'g': + who |= S_ISGID|S_IRWXG; + break; + case 'o': + who |= S_IRWXO; + break; + default: + goto getop; + } + } + +getop: if ((op = *p++) != '+' && op != '-' && op != '=') { + errno = EINVAL; + goto out; + } + if (op == '=') + equalopdone = 0; + + who &= ~S_ISTXT; + for (perm = 0, permXbits = 0;; ++p) { + switch (*p) { + case 'r': + perm |= S_IRUSR|S_IRGRP|S_IROTH; + break; + case 's': + /* If only "other" bits ignore set-id. */ + if (!who || who & ~S_IRWXO) + perm |= S_ISUID|S_ISGID; + break; + case 't': + /* If only "other" bits ignore sticky. */ + if (!who || who & ~S_IRWXO) { + who |= S_ISTXT; + perm |= S_ISTXT; + } + break; + case 'w': + perm |= S_IWUSR|S_IWGRP|S_IWOTH; + break; + case 'X': + permXbits = S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'x': + perm |= S_IXUSR|S_IXGRP|S_IXOTH; + break; + case 'u': + case 'g': + case 'o': + /* + * When ever we hit 'u', 'g', or 'o', we have + * to flush out any partial mode that we have, + * and then do the copying of the mode bits. + */ + if (perm) { + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (op == '=') + equalopdone = 1; + if (op == '+' && permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + ADDCMD(*p, who, op, mask); + break; + + default: + /* + * Add any permissions that we haven't already + * done. + */ + if (perm || (op == '=' && !equalopdone)) { + if (op == '=') + equalopdone = 1; + ADDCMD(op, who, perm, mask); + perm = 0; + } + if (permXbits) { + ADDCMD('X', who, permXbits, mask); + permXbits = 0; + } + goto apply; + } + } + +apply: if (!*p) + break; + if (*p != ',') + goto getop; + ++p; + } + set->cmd = 0; +#ifdef SETMODE_DEBUG + (void)printf("Before compress_mode()\n"); + dumpmode(saveset); +#endif + compress_mode(saveset); +#ifdef SETMODE_DEBUG + (void)printf("After compress_mode()\n"); + dumpmode(saveset); +#endif + return (saveset); +out: + serrno = errno; + free(saveset); + errno = serrno; + return NULL; +} + +static mode_t +get_current_umask(void) +{ + sigset_t sigset, sigoset; + size_t len; + mode_t mask; + u_short smask; + +#ifdef KERN_PROC_UMASK + /* + * First try requesting the umask without temporarily modifying it. + * Note that this does not work if the sysctl + * security.bsd.unprivileged_proc_debug is set to 0. + */ + len = sizeof(smask); + if (sysctl((int[4]){ CTL_KERN, KERN_PROC, KERN_PROC_UMASK, 0 }, + 4, &smask, &len, NULL, 0) == 0) + return (smask); +#endif + /* + * Since it's possible that the caller is opening files inside a signal + * handler, protect them as best we can. + */ + sigfillset(&sigset); + (void)__libc_sigprocmask(SIG_BLOCK, &sigset, &sigoset); + (void)umask(mask = umask(0)); + (void)__libc_sigprocmask(SIG_SETMASK, &sigoset, NULL); + return (mask); +} + +static BITCMD * +addcmd(BITCMD *set, mode_t op, mode_t who, mode_t oparg, mode_t mask) +{ + switch (op) { + case '=': + set->cmd = '-'; + set->bits = who ? who : STANDARD_BITS; + set++; + + op = '+'; + /* FALLTHROUGH */ + case '+': + case '-': + case 'X': + set->cmd = op; + set->bits = (who ? who : mask) & oparg; + break; + + case 'u': + case 'g': + case 'o': + set->cmd = op; + if (who) { + set->cmd2 = ((who & S_IRUSR) ? CMD2_UBITS : 0) | + ((who & S_IRGRP) ? CMD2_GBITS : 0) | + ((who & S_IROTH) ? CMD2_OBITS : 0); + set->bits = (mode_t)~0; + } else { + set->cmd2 = CMD2_UBITS | CMD2_GBITS | CMD2_OBITS; + set->bits = mask; + } + + if (oparg == '+') + set->cmd2 |= CMD2_SET; + else if (oparg == '-') + set->cmd2 |= CMD2_CLR; + else if (oparg == '=') + set->cmd2 |= CMD2_SET|CMD2_CLR; + break; + } + return (set + 1); +} + +#ifdef SETMODE_DEBUG +static void +dumpmode(BITCMD *set) +{ + for (; set->cmd; ++set) + (void)printf("cmd: '%c' bits %04o%s%s%s%s%s%s\n", + set->cmd, set->bits, set->cmd2 ? " cmd2:" : "", + set->cmd2 & CMD2_CLR ? " CLR" : "", + set->cmd2 & CMD2_SET ? " SET" : "", + set->cmd2 & CMD2_UBITS ? " UBITS" : "", + set->cmd2 & CMD2_GBITS ? " GBITS" : "", + set->cmd2 & CMD2_OBITS ? " OBITS" : ""); +} +#endif + +/* + * Given an array of bitcmd structures, compress by compacting consecutive + * '+', '-' and 'X' commands into at most 3 commands, one of each. The 'u', + * 'g' and 'o' commands continue to be separate. They could probably be + * compacted, but it's not worth the effort. + */ +static void +compress_mode(BITCMD *set) +{ + BITCMD *nset; + int setbits, clrbits, Xbits, op; + + for (nset = set;;) { + /* Copy over any 'u', 'g' and 'o' commands. */ + while ((op = nset->cmd) != '+' && op != '-' && op != 'X') { + *set++ = *nset++; + if (!op) + return; + } + + for (setbits = clrbits = Xbits = 0;; nset++) { + if ((op = nset->cmd) == '-') { + clrbits |= nset->bits; + setbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == '+') { + setbits |= nset->bits; + clrbits &= ~nset->bits; + Xbits &= ~nset->bits; + } else if (op == 'X') + Xbits |= nset->bits & ~setbits; + else + break; + } + if (clrbits) { + set->cmd = '-'; + set->cmd2 = 0; + set->bits = clrbits; + set++; + } + if (setbits) { + set->cmd = '+'; + set->cmd2 = 0; + set->bits = setbits; + set++; + } + if (Xbits) { + set->cmd = 'X'; + set->cmd2 = 0; + set->bits = Xbits; + set++; + } + } +} diff --git a/lib/libc/gen/setproctitle.3 b/lib/libc/gen/setproctitle.3 new file mode 100644 index 000000000000..087cbe4b84e9 --- /dev/null +++ b/lib/libc/gen/setproctitle.3 @@ -0,0 +1,139 @@ +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.\" Copyright (c) 1995 Peter Wemm +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" The following requests are required for all man pages. +.Dd November 28, 2022 +.Dt SETPROCTITLE 3 +.Os +.Sh NAME +.Nm setproctitle +.Nm setproctitle_fast +.Nd set process title +.Sh SYNOPSIS +.In unistd.h +.Ft void +.Fn setproctitle "const char *fmt" "..." +.Ft void +.Fn setproctitle_fast "const char *fmt" "..." +.Sh DESCRIPTION +The +.Fn setproctitle +library routine sets the process title that appears on the +.Xr ps 1 +command. +The +.Fn setproctitle_fast +variant is optimized for high frequency updates, but may make the +.Xr ps 1 +command slightly slower by not updating the kernel cache of the program +arguments. +.Pp +The title is set from the executable's name, followed by the +result of a +.Xr printf 3 +style expansion of the arguments as specified by the +.Va fmt +argument. +If the +.Va fmt +argument begins with a +.Dq - +character, the executable's name is skipped. +.Pp +If +.Va fmt +is NULL, the process title is restored. +.Sh EXAMPLES +To set the title on a daemon to indicate its activity: +.Bd -literal -offset indent +setproctitle("talking to %s", inet_ntoa(addr)); +.Ed +.Sh SEE ALSO +.Xr ps 1 , +.Xr w 1 , +.Xr kvm 3 , +.Xr kvm_getargv 3 , +.Xr printf 3 , +.Xr setprogname 3 +.Sh STANDARDS +The +.Fn setproctitle +function +is implicitly non-standard. +Other methods of causing the +.Xr ps 1 +command line to change, including copying over the argv[0] string are +also implicitly non-portable. +It is preferable to use an operating system +supplied +.Fn setproctitle +if present. +.Pp +Unfortunately, it is possible that there are other calling conventions +to other versions of +.Fn setproctitle , +although none have been found by the author as yet. +This is believed to be +the predominant convention. +.Pp +It is thought that the implementation is compatible with other systems, +including +.Nx +and +.Bsx . +.Sh HISTORY +The +.Fn setproctitle +function +first appeared in +.Fx 2.2 . +The +.Fn setproctitle_fast +function first appeared in +.Fx 12 . +Other operating systems have +similar functions. +.Sh AUTHORS +.An -nosplit +.An Peter Wemm Aq Mt peter@FreeBSD.org +stole the idea from the +.Sy "Sendmail 8.7.3" +source code by +.An Eric Allman Aq Mt eric@sendmail.org . +.Sh BUGS +Never pass a string with user-supplied data as a format without using +.Ql %s . +An attacker can put format specifiers in the string to mangle your stack, +leading to a possible security hole. +This holds true even if the string was built using a function like +.Fn snprintf , +as the resulting string may still contain user-supplied conversion specifiers +for later interpolation by +.Fn setproctitle . +.Pp +Always use the proper secure idiom: +.Pp +.Dl setproctitle("%s", string); diff --git a/lib/libc/gen/setproctitle.c b/lib/libc/gen/setproctitle.c new file mode 100644 index 000000000000..715951a8c96d --- /dev/null +++ b/lib/libc/gen/setproctitle.c @@ -0,0 +1,218 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1995 Peter Wemm + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/elf_common.h> +#include <sys/exec.h> +#include <sys/sysctl.h> + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" + +/* + * Older FreeBSD 2.0, 2.1 and 2.2 had different ps_strings structures and + * in different locations. + * 1: old_ps_strings at the very top of the stack. + * 2: old_ps_strings at SPARE_USRSPACE below the top of the stack. + * 3: ps_strings at the very top of the stack. + * We only support a kernel providing #3 style ps_strings. + * + * For historical purposes, a definition of the old ps_strings structure + * and location is preserved below: +struct old_ps_strings { + char *old_ps_argvstr; + int old_ps_nargvstr; + char *old_ps_envstr; + int old_ps_nenvstr; +}; +#define OLD_PS_STRINGS ((struct old_ps_strings *) \ + (USRSTACK - SPARE_USRSPACE - sizeof(struct old_ps_strings))) + */ + +#include <stdarg.h> + +#define SPT_BUFSIZE 2048 /* from other parts of sendmail */ + +static char * +setproctitle_internal(const char *fmt, va_list ap) +{ + static struct ps_strings *ps_strings; + static char *buf = NULL; + static char *obuf = NULL; + static char **oargv; + static int oargc = -1; + static char *nargv[2] = { NULL, NULL }; + char **nargvp; + int nargc; + int i; + size_t len; + unsigned long ul_ps_strings; + + if (buf == NULL) { + buf = malloc(SPT_BUFSIZE); + if (buf == NULL) + return (NULL); + nargv[0] = buf; + } + + if (obuf == NULL ) { + obuf = malloc(SPT_BUFSIZE); + if (obuf == NULL) + return (NULL); + *obuf = '\0'; + } + + if (fmt) { + buf[SPT_BUFSIZE - 1] = '\0'; + + if (fmt[0] == '-') { + /* skip program name prefix */ + fmt++; + len = 0; + } else { + /* print program name heading for grep */ + (void)snprintf(buf, SPT_BUFSIZE, "%s: ", _getprogname()); + len = strlen(buf); + } + + /* print the argument string */ + (void)vsnprintf(buf + len, SPT_BUFSIZE - len, fmt, ap); + + nargvp = nargv; + nargc = 1; + } else if (*obuf != '\0') { + /* Idea from NetBSD - reset the title on fmt == NULL */ + nargvp = oargv; + nargc = oargc; + } else + /* Nothing to restore */ + return (NULL); + + if (ps_strings == NULL) + (void)_elf_aux_info(AT_PS_STRINGS, &ps_strings, + sizeof(ps_strings)); + + if (ps_strings == NULL) { + len = sizeof(ul_ps_strings); + if (sysctlbyname("kern.ps_strings", &ul_ps_strings, &len, NULL, + 0) == -1) + return (NULL); + ps_strings = (struct ps_strings *)ul_ps_strings; + } + + if (ps_strings == NULL) + return (NULL); + + /* + * PS_STRINGS points to zeroed memory on a style #2 kernel. + * Should not happen. + */ + if (ps_strings->ps_argvstr == NULL) + return (NULL); + + /* style #3 */ + if (oargc == -1) { + /* Record our original args */ + oargc = ps_strings->ps_nargvstr; + oargv = ps_strings->ps_argvstr; + for (i = len = 0; i < oargc; i++) { + /* + * The program may have scribbled into its + * argv array, e.g., to remove some arguments. + * If that has happened, break out before + * trying to call strlen on a NULL pointer. + */ + if (oargv[i] == NULL) { + oargc = i; + break; + } + snprintf(obuf + len, SPT_BUFSIZE - len, "%s%s", + len != 0 ? " " : "", oargv[i]); + if (len != 0) + len++; + len += strlen(oargv[i]); + if (len >= SPT_BUFSIZE) + break; + } + } + ps_strings->ps_nargvstr = nargc; + ps_strings->ps_argvstr = nargvp; + + return (nargvp[0]); +} + +static int fast_update = 0; + +void +setproctitle_fast(const char *fmt, ...) +{ + va_list ap; + char *buf; + int oid[4]; + + va_start(ap, fmt); + buf = setproctitle_internal(fmt, ap); + va_end(ap); + + if (buf && !fast_update) { + /* Tell the kernel to start looking in user-space */ + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = -1; + sysctl(oid, 4, 0, 0, "", 0); + fast_update = 1; + } +} + +void +setproctitle(const char *fmt, ...) +{ + va_list ap; + char *buf; + int oid[4]; + + va_start(ap, fmt); + buf = setproctitle_internal(fmt, ap); + va_end(ap); + + if (buf != NULL) { + /* Set the title into the kernel cached command line */ + oid[0] = CTL_KERN; + oid[1] = KERN_PROC; + oid[2] = KERN_PROC_ARGS; + oid[3] = -1; + sysctl(oid, 4, 0, 0, buf, strlen(buf) + 1); + fast_update = 0; + } +} diff --git a/lib/libc/gen/setprogname.c b/lib/libc/gen/setprogname.c new file mode 100644 index 000000000000..853c5f277386 --- /dev/null +++ b/lib/libc/gen/setprogname.c @@ -0,0 +1,16 @@ +#include <stdlib.h> +#include <string.h> + +#include "libc_private.h" + +void +setprogname(const char *progname) +{ + const char *p; + + p = strrchr(progname, '/'); + if (p != NULL) + __progname = p + 1; + else + __progname = progname; +} diff --git a/lib/libc/gen/sig2str.c b/lib/libc/gen/sig2str.c new file mode 100644 index 000000000000..869a09ab9db4 --- /dev/null +++ b/lib/libc/gen/sig2str.c @@ -0,0 +1,113 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 Ricardo Branco <rbranco@suse.de>. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Translate between signal names and numbers + */ +#include "namespace.h" +#include <ctype.h> +#include <limits.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ssp/ssp.h> +#include "un-namespace.h" + +static const char rtmin_str[] = "RTMIN"; +static const char rtmax_str[] = "RTMAX"; + +int +__ssp_real(sig2str)(int signum, char *str) +{ + if (signum <= 0 || signum > SIGRTMAX) + return (-1); + + if (signum < sys_nsig) + (void)strlcpy(str, sys_signame[signum], SIG2STR_MAX); + else if (signum < SIGRTMIN) + (void)snprintf(str, SIG2STR_MAX, "%d", signum); + else if (signum == SIGRTMIN) + (void)strlcpy(str, rtmin_str, SIG2STR_MAX); + else if (signum == SIGRTMAX) + (void)strlcpy(str, rtmax_str, SIG2STR_MAX); + else if (signum <= (SIGRTMIN + SIGRTMAX) / 2) + (void)snprintf(str, SIG2STR_MAX, "%s+%d", + rtmin_str, signum - SIGRTMIN); + else + (void)snprintf(str, SIG2STR_MAX, "%s-%d", + rtmax_str, SIGRTMAX - signum); + + return (0); +} + +int +str2sig(const char * restrict str, int * restrict pnum) +{ + const char *errstr; + long long n; + int sig; + int rtend = sizeof(rtmin_str) - 1; + + if (strncasecmp(str, "SIG", 3) == 0) + str += 3; + + if (strncasecmp(str, rtmin_str, sizeof(rtmin_str) - 1) == 0 || + strncasecmp(str, rtmax_str, sizeof(rtmax_str) - 1) == 0) { + sig = (toupper(str[4]) == 'X') ? SIGRTMAX : SIGRTMIN; + n = 0; + if (str[rtend] == '+' || str[rtend] == '-') { + n = strtonum(str + rtend, INT_MIN, INT_MAX, &errstr); + if (n == 0 || errstr != NULL) + return (-1); + } else if (str[rtend] != '\0') { + return (-1); + } + sig += (int)n; + if (sig < SIGRTMIN || sig > SIGRTMAX) + return (-1); + *pnum = sig; + return (0); + } + + if (isdigit((unsigned char)str[0])) { + n = strtonum(str, 1, SIGRTMAX, &errstr); + if (errstr == NULL) { + *pnum = (int)n; + return (0); + } + } + + for (sig = 1; sig < sys_nsig; sig++) { + if (strcasecmp(sys_signame[sig], str) == 0) { + *pnum = sig; + return (0); + } + } + + return (-1); +} diff --git a/lib/libc/gen/siginterrupt.3 b/lib/libc/gen/siginterrupt.3 new file mode 100644 index 000000000000..4e286f28df7c --- /dev/null +++ b/lib/libc/gen/siginterrupt.3 @@ -0,0 +1,116 @@ +.\" Copyright (c) 1985, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 4, 1993 +.Dt SIGINTERRUPT 3 +.Os +.Sh NAME +.Nm siginterrupt +.Nd allow signals to interrupt system calls +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In signal.h +.Ft int +.Fn siginterrupt "int sig" "int flag" +.Sh DESCRIPTION +The +.Fn siginterrupt +function +is used to change the system call restart +behavior when a system call is interrupted by the specified signal. +If the flag is false (0), then system calls will be restarted if +they are interrupted by the specified signal +and no data has been transferred yet. +System call restart has been the default behavior since +.Bx 4.2 , +and is the default behaviour for +.Xr signal 3 +on +.Fx . +.Pp +If the flag is true (1), +then restarting of system calls is disabled. +If a system call is interrupted by the specified signal +and no data has been transferred, +the system call will return \-1 with the global variable +.Va errno +set to +.Er EINTR . +Interrupted system calls that have started transferring +data will return the amount of data actually transferred. +System call interrupt is the signal behavior found on +.Bx 4.1 +and +.At V +systems. +.Pp +Note that the new +.Bx 4.2 +signal handling semantics are not +altered in any other way. +Most notably, signal handlers always remain installed until +explicitly changed by a subsequent +.Xr sigaction 2 +call, and the signal mask operates as documented in +.Xr sigaction 2 . +Programs may switch between restartable and interruptible +system call operation as often as desired in the execution of a program. +.Pp +Issuing a +.Fn siginterrupt 3 +call during the execution of a signal handler will cause +the new action to take place on the next signal to be caught. +.Sh NOTES +This library routine uses an extension of the +.Xr sigaction 2 +system call that is not available in +.Bx 4.2 , +hence it should not be used if backward compatibility is needed. +.Sh RETURN VALUES +.Rv -std siginterrupt +.Sh ERRORS +The +.Fn siginterrupt +call fails if: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sig +argument +is not a valid signal number. +.El +.Sh SEE ALSO +.Xr sigaction 2 , +.Xr sigprocmask 2 , +.Xr sigsuspend 2 , +.Xr signal 3 +.Sh HISTORY +The +.Fn siginterrupt +function appeared in +.Bx 4.3 . diff --git a/lib/libc/gen/siginterrupt.c b/lib/libc/gen/siginterrupt.c new file mode 100644 index 000000000000..0a05e89982dc --- /dev/null +++ b/lib/libc/gen/siginterrupt.c @@ -0,0 +1,58 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <signal.h> +#include "un-namespace.h" +#include "libc_private.h" + +/* + * Set signal state to prevent restart of system calls + * after an instance of the indicated signal. + */ +int +siginterrupt(int sig, int flag) +{ + extern sigset_t _sigintr __hidden; + struct sigaction sa; + int ret; + + if ((ret = __libc_sigaction(sig, (struct sigaction *)0, &sa)) < 0) + return (ret); + if (flag) { + sigaddset(&_sigintr, sig); + sa.sa_flags &= ~SA_RESTART; + } else { + sigdelset(&_sigintr, sig); + sa.sa_flags |= SA_RESTART; + } + return (__libc_sigaction(sig, &sa, (struct sigaction *)0)); +} diff --git a/lib/libc/gen/siglist.c b/lib/libc/gen/siglist.c new file mode 100644 index 000000000000..c1d0a8d425e1 --- /dev/null +++ b/lib/libc/gen/siglist.c @@ -0,0 +1,103 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <signal.h> + +const char *const sys_signame[NSIG] = { + [0] = "Signal 0", + [SIGHUP] = "HUP", + [SIGINT] = "INT", + [SIGQUIT] = "QUIT", + [SIGILL] = "ILL", + [SIGTRAP] = "TRAP", + [SIGABRT] = "ABRT", + [SIGEMT] = "EMT", + [SIGFPE] = "FPE", + [SIGKILL] = "KILL", + [SIGBUS] = "BUS", + [SIGSEGV] = "SEGV", + [SIGSYS] = "SYS", + [SIGPIPE] = "PIPE", + [SIGALRM] = "ALRM", + [SIGTERM] = "TERM", + [SIGURG] = "URG", + [SIGSTOP] = "STOP", + [SIGTSTP] = "TSTP", + [SIGCONT] = "CONT", + [SIGCHLD] = "CHLD", + [SIGTTIN] = "TTIN", + [SIGTTOU] = "TTOU", + [SIGIO] = "IO", + [SIGXCPU] = "XCPU", + [SIGXFSZ] = "XFSZ", + [SIGVTALRM] = "VTALRM", + [SIGPROF] = "PROF", + [SIGWINCH] = "WINCH", + [SIGINFO] = "INFO", + [SIGUSR1] = "USR1", + [SIGUSR2] = "USR2", +}; + +const char *const sys_siglist[NSIG] = { + [0] = "Signal 0", + [SIGHUP] = "Hangup", + [SIGINT] = "Interrupt", + [SIGQUIT] = "Quit", + [SIGILL] = "Illegal instruction", + [SIGTRAP] = "Trace/BPT trap", + [SIGABRT] = "Abort trap", + [SIGEMT] = "EMT trap", + [SIGFPE] = "Floating point exception", + [SIGKILL] = "Killed", + [SIGBUS] = "Bus error", + [SIGSEGV] = "Segmentation fault", + [SIGSYS] = "Bad system call", + [SIGPIPE] = "Broken pipe", + [SIGALRM] = "Alarm clock", + [SIGTERM] = "Terminated", + [SIGURG] = "Urgent I/O condition", + [SIGSTOP] = "Suspended (signal)", + [SIGTSTP] = "Suspended", + [SIGCONT] = "Continued", + [SIGCHLD] = "Child exited", + [SIGTTIN] = "Stopped (tty input)", + [SIGTTOU] = "Stopped (tty output)", + [SIGIO] = "I/O possible", + [SIGXCPU] = "Cputime limit exceeded", + [SIGXFSZ] = "Filesize limit exceeded", + [SIGVTALRM] = "Virtual timer expired", + [SIGPROF] = "Profiling timer expired", + [SIGWINCH] = "Window size changes", + [SIGINFO] = "Information request", + [SIGUSR1] = "User defined signal 1", + [SIGUSR2] = "User defined signal 2", +}; +const int sys_nsig = sizeof(sys_siglist) / sizeof(sys_siglist[0]); diff --git a/lib/libc/gen/signal.3 b/lib/libc/gen/signal.3 new file mode 100644 index 000000000000..56e77325eed8 --- /dev/null +++ b/lib/libc/gen/signal.3 @@ -0,0 +1,273 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd December 1, 2017 +.Dt SIGNAL 3 +.Os +.Sh NAME +.Nm signal +.Nd simplified software signal facilities +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In signal.h +.\" The following is Quite Ugly, but syntactically correct. +.\" Don't try to fix it. +.Ft void +.Fn \*(lp*signal "int sig" "void \*(lp*func\*(rp\*(lpint\*(rp\*(rp\*(rp\*(lpint" +.Pp +or in +.Fx Ap s +equivalent but easier to read typedef'd version: +.Ft typedef "void \*(lp*sig_t\*(rp \*(lpint\*(rp" ; +.Pp +.Ft sig_t +.Fn signal "int sig" "sig_t func" +.Sh DESCRIPTION +This +.Fn signal +facility +is a simplified interface to the more general +.Xr sigaction 2 +facility. +.Pp +Signals allow the manipulation of a process from outside its +domain as well as allowing the process to manipulate itself or +copies of itself (children). +There are two general types of signals: +those that cause termination of a process and those that do not. +Signals which cause termination of a program might result from +an irrecoverable error or might be the result of a user at a terminal +typing the `interrupt' character. +Signals are used when a process is stopped because it wishes to access +its control terminal while in the background (see +.Xr tty 4 ) . +Signals are optionally generated +when a process resumes after being stopped, +when the status of child processes changes, +or when input is ready at the control terminal. +Most signals result in the termination of the process receiving them +if no action +is taken; some signals instead cause the process receiving them +to be stopped, or are simply discarded if the process has not +requested otherwise. +Except for the +.Dv SIGKILL +and +.Dv SIGSTOP +signals, the +.Fn signal +function allows for a signal to be caught, to be ignored, or to generate +an interrupt. +These signals are defined in the file +.In signal.h : +.Bl -column No ".Dv SIGVTALRM" "create core image" +.It Sy "Num" Ta Sy "Name" Ta Sy "Default Action" Ta Sy "Description" +.It 1 Ta Dv SIGHUP Ta "terminate process" Ta "terminal line hangup" +.It 2 Ta Dv SIGINT Ta "terminate process" Ta "interrupt program" +.It 3 Ta Dv SIGQUIT Ta "create core image" Ta "quit program" +.It 4 Ta Dv SIGILL Ta "create core image" Ta "illegal instruction" +.It 5 Ta Dv SIGTRAP Ta "create core image" Ta "trace trap" +.It 6 Ta Dv SIGABRT Ta "create core image" Ta "abort program" +(formerly +.Dv SIGIOT ) +.It 7 Ta Dv SIGEMT Ta "create core image" Ta "emulate instruction executed" +.It 8 Ta Dv SIGFPE Ta "create core image" Ta "floating-point exception" +.It 9 Ta Dv SIGKILL Ta "terminate process" Ta "kill program" +.It 10 Ta Dv SIGBUS Ta "create core image" Ta "bus error" +.It 11 Ta Dv SIGSEGV Ta "create core image" Ta "segmentation violation" +.It 12 Ta Dv SIGSYS Ta "create core image" Ta "non-existent system call invoked" +.It 13 Ta Dv SIGPIPE Ta "terminate process" Ta "write on a pipe with no reader" +.It 14 Ta Dv SIGALRM Ta "terminate process" Ta "real-time timer expired" +.It 15 Ta Dv SIGTERM Ta "terminate process" Ta "software termination signal" +.It 16 Ta Dv SIGURG Ta "discard signal" Ta "urgent condition present on socket" +.It 17 Ta Dv SIGSTOP Ta "stop process" Ta "stop (cannot be caught or ignored)" +.It 18 Ta Dv SIGTSTP Ta "stop process" Ta "stop signal generated from keyboard" +.It 19 Ta Dv SIGCONT Ta "discard signal" Ta "continue after stop" +.It 20 Ta Dv SIGCHLD Ta "discard signal" Ta "child status has changed" +.It 21 Ta Dv SIGTTIN Ta "stop process" Ta "background read attempted from" +control terminal +.It 22 Ta Dv SIGTTOU Ta "stop process" Ta "background write attempted to" +control terminal +.It 23 Ta Dv SIGIO Ta "discard signal" Ta Tn "I/O" +is possible on a descriptor (see +.Xr fcntl 2 ) +.It 24 Ta Dv SIGXCPU Ta "terminate process" Ta "cpu time limit exceeded (see" +.Xr setrlimit 2 ) +.It 25 Ta Dv SIGXFSZ Ta "terminate process" Ta "file size limit exceeded (see" +.Xr setrlimit 2 ) +.It 26 Ta Dv SIGVTALRM Ta "terminate process" Ta "virtual time alarm (see" +.Xr setitimer 2 ) +.It 27 Ta Dv SIGPROF Ta "terminate process" Ta "profiling timer alarm (see" +.Xr setitimer 2 ) +.It 28 Ta Dv SIGWINCH Ta "discard signal" Ta "Window size change" +.It 29 Ta Dv SIGINFO Ta "discard signal" Ta "status request from keyboard" +.It 30 Ta Dv SIGUSR1 Ta "terminate process" Ta "User defined signal 1" +.It 31 Ta Dv SIGUSR2 Ta "terminate process" Ta "User defined signal 2" +.It 32 Ta Dv SIGTHR Ta "terminate process" Ta "thread interrupt" +.It 33 Ta Dv SIGLIBRT Ta "terminate process" Ta "real-time library interrupt" +.El +.Pp +The +.Fa sig +argument specifies which signal was received. +The +.Fa func +procedure allows a user to choose the action upon receipt of a signal. +To set the default action of the signal to occur as listed above, +.Fa func +should be +.Dv SIG_DFL . +A +.Dv SIG_DFL +resets the default action. +To ignore the signal +.Fa func +should be +.Dv SIG_IGN . +This will cause subsequent instances of the signal to be ignored +and pending instances to be discarded. +If +.Dv SIG_IGN +is not used, +further occurrences of the signal are +automatically blocked and +.Fa func +is called. +.Pp +The handled signal is unblocked when the +function returns and +the process continues from where it left off when the signal occurred. +.Bf -symbolic +Unlike previous signal facilities, the handler +func() remains installed after a signal has been delivered. +.Ef +.Pp +For some system calls, if a signal is caught while the call is +executing and the call is prematurely terminated, +the call is automatically restarted. +Any handler installed with +.Xr signal 3 +will have the +.Dv SA_RESTART +flag set, meaning that any restartable system call will not return on +receipt of a signal. +The affected system calls include +.Xr read 2 , +.Xr write 2 , +.Xr sendto 2 , +.Xr recvfrom 2 , +.Xr sendmsg 2 +and +.Xr recvmsg 2 +on a communications channel or a low speed device +and during a +.Xr ioctl 2 +or +.Xr wait 2 . +However, calls that have already committed are not restarted, +but instead return a partial success (for example, a short read count). +These semantics could be changed with +.Xr siginterrupt 3 . +.Pp +When a process which has installed signal handlers forks, +the child process inherits the signals. +All caught signals may be reset to their default action by a call +to the +.Xr execve 2 +function; +ignored signals remain ignored. +.Pp +If a process explicitly specifies +.Dv SIG_IGN +as the action for the signal +.Dv SIGCHLD , +the system will not create zombie processes when children +of the calling process exit. +As a consequence, the system will discard the exit status +from the child processes. +If the calling process subsequently issues a call to +.Xr wait 2 +or equivalent, it will block until all of the calling process's +children terminate, and then return a value of \-1 with +.Va errno +set to +.Er ECHILD . +.Pp +See +.Xr sigaction 2 +for a list of functions +that are considered safe for use in signal handlers. +.Sh RETURN VALUES +The previous action is returned on a successful call. +Otherwise, SIG_ERR is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +The +.Fn signal +function +will fail and no action will take place if one of the +following occur: +.Bl -tag -width Er +.It Bq Er EINVAL +The +.Fa sig +argument +is not a valid signal number. +.It Bq Er EINVAL +An attempt is made to ignore or supply a handler for +.Dv SIGKILL +or +.Dv SIGSTOP . +.El +.Sh SEE ALSO +.Xr kill 1 , +.Xr kill 2 , +.Xr ptrace 2 , +.Xr sigaction 2 , +.Xr sigaltstack 2 , +.Xr sigprocmask 2 , +.Xr sigsuspend 2 , +.Xr wait 2 , +.Xr fpsetmask 3 , +.Xr setjmp 3 , +.Xr siginterrupt 3 , +.Xr tty 4 +.Sh HISTORY +The +.Fn signal +function appeared in +.At v4 . +The current +.Nm +facility appeared in +.Bx 4.0 . +The option to avoid the creation of child zombies through ignoring +.Dv SIGCHLD +appeared in +.Fx 5.0 . diff --git a/lib/libc/gen/signal.c b/lib/libc/gen/signal.c new file mode 100644 index 000000000000..dce06bba3678 --- /dev/null +++ b/lib/libc/gen/signal.c @@ -0,0 +1,55 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1985, 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Almost backwards compatible signal. + */ +#include "namespace.h" +#include <signal.h> +#include "un-namespace.h" +#include "libc_private.h" + +sigset_t _sigintr __hidden; /* shared with siginterrupt */ + +sig_t +signal(int s, sig_t a) +{ + struct sigaction sa, osa; + + sa.sa_handler = a; + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + if (!sigismember(&_sigintr, s)) + sa.sa_flags |= SA_RESTART; + if (__libc_sigaction(s, &sa, &osa) < 0) + return (SIG_ERR); + return (osa.sa_handler); +} diff --git a/lib/libc/gen/sigsetops.3 b/lib/libc/gen/sigsetops.3 new file mode 100644 index 000000000000..109b1d9d4a8c --- /dev/null +++ b/lib/libc/gen/sigsetops.3 @@ -0,0 +1,163 @@ +.\" Copyright (c) 1983, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 29, 2019 +.Dt SIGSETOPS 3 +.Os +.Sh NAME +.Nm sigemptyset , +.Nm sigfillset , +.Nm sigaddset , +.Nm sigandset , +.Nm sigdelset , +.Nm sigisemptyset , +.Nm sigismember , +.Nm sigorset +.Nd manipulate signal sets +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In signal.h +.Ft int +.Fn sigemptyset "sigset_t *set" +.Ft int +.Fn sigfillset "sigset_t *set" +.Ft int +.Fn sigaddset "sigset_t *set" "int signo" +.Ft int +.Fn sigandset "sigset_t *set" "const sigset_t *left" "const sigset_t *right" +.Ft int +.Fn sigdelset "sigset_t *set" "int signo" +.Ft int +.Fn sigisemptyset "const sigset_t *set" +.Ft int +.Fn sigismember "const sigset_t *set" "int signo" +.Ft int +.Fn sigorset "sigset_t *set" "const sigset_t *left" "const sigset_t *right" +.Sh DESCRIPTION +These functions manipulate signal sets stored in a +.Fa sigset_t . +Either +.Fn sigemptyset +or +.Fn sigfillset +must be called for every object of type +.Fa sigset_t +before any other use of the object. +.Pp +The +.Fn sigemptyset +function initializes a signal set to be empty. +.Pp +The +.Fn sigfillset +function initializes a signal set to contain all signals. +.Pp +The +.Fn sigaddset +function adds the specified signal +.Fa signo +to the signal set. +.Pp +The +.Fn sigandset +function sets the specified +.Fa set +to the logical AND of all signals from the +.Fa left +and +.Fa right +signal sets. +.Pp +The +.Fn sigdelset +function deletes the specified signal +.Fa signo +from the signal set. +.Pp +The +.Fn sigisemptyset +function returns whether the specified +.Fa set +is empty or not. +.Pp +The +.Fn sigismember +function returns whether a specified signal +.Fa signo +is contained in the signal set. +.Pp +The +.Fn sigorset +function sets the specified +.Fa set +to the logical OR of all signals from the +.Fa left +and +.Fa right +signal sets. +.Sh RETURN VALUES +The +.Fn sigisemptyset +function returns 1 +if the set is empty, 0 otherwise. +.Pp +The +.Fn sigismember +function returns 1 +if the signal is a member of the set, +0 otherwise. +.Pp +The other functions return 0 upon success. +A \-1 return value +indicates an error occurred and the global variable +.Va errno +is set to indicate the reason. +.Sh ERRORS +These functions could fail if one of the following occurs: +.Bl -tag -width Er +.It Bq Er EINVAL +.Fa signo +has an invalid value. +.El +.Sh SEE ALSO +.Xr kill 2 , +.Xr sigaction 2 , +.Xr sigpending 2 , +.Xr sigprocmask 2 , +.Xr sigsuspend 2 +.Sh STANDARDS +The +.Fn sigandset , +.Fn sigisemptyset , +and +.Fn sigorset +functions are FreeBSD extensions, compatible with functions of the same name +provided by both musl libc and GNU libc. +.Pp +The rest of these functions are defined by +.St -p1003.1-88 . diff --git a/lib/libc/gen/sigsetops.c b/lib/libc/gen/sigsetops.c new file mode 100644 index 000000000000..3e22b0dba5e9 --- /dev/null +++ b/lib/libc/gen/sigsetops.c @@ -0,0 +1,119 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <errno.h> +#include <signal.h> + +int +sigaddset(sigset_t *set, int signo) +{ + + if (signo <= 0 || signo > _SIG_MAXSIG) { + errno = EINVAL; + return (-1); + } + set->__bits[_SIG_WORD(signo)] |= _SIG_BIT(signo); + return (0); +} + +int +sigdelset(sigset_t *set, int signo) +{ + + if (signo <= 0 || signo > _SIG_MAXSIG) { + errno = EINVAL; + return (-1); + } + set->__bits[_SIG_WORD(signo)] &= ~_SIG_BIT(signo); + return (0); +} + +int +sigemptyset(sigset_t *set) +{ + int i; + + for (i = 0; i < _SIG_WORDS; i++) + set->__bits[i] = 0; + return (0); +} + +int +sigfillset(sigset_t *set) +{ + int i; + + for (i = 0; i < _SIG_WORDS; i++) + set->__bits[i] = ~0U; + return (0); +} + +int +sigorset(sigset_t *dest, const sigset_t *left, const sigset_t *right) +{ + int i; + + for (i = 0; i < _SIG_WORDS; i++) + dest->__bits[i] = left->__bits[i] | right->__bits[i]; + return (0); +} + +int +sigandset(sigset_t *dest, const sigset_t *left, const sigset_t *right) +{ + int i; + + for (i = 0; i < _SIG_WORDS; i++) + dest->__bits[i] = left->__bits[i] & right->__bits[i]; + return (0); +} + +int +sigisemptyset(const sigset_t *set) +{ + int i; + + for (i = 0; i < _SIG_WORDS; i++) + if (set->__bits[i] != 0) + return (0); + return (1); +} + +int +sigismember(const sigset_t *set, int signo) +{ + + if (signo <= 0 || signo > _SIG_MAXSIG) { + errno = EINVAL; + return (-1); + } + return ((set->__bits[_SIG_WORD(signo)] & _SIG_BIT(signo)) ? 1 : 0); +} diff --git a/lib/libc/gen/sleep.c b/lib/libc/gen/sleep.c new file mode 100644 index 000000000000..e32d434d4d33 --- /dev/null +++ b/lib/libc/gen/sleep.c @@ -0,0 +1,67 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <errno.h> +#include <limits.h> +#include <time.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" + +unsigned int __sleep(unsigned int); + +unsigned int +__sleep(unsigned int seconds) +{ + struct timespec time_to_sleep; + struct timespec time_remaining; + + /* + * Avoid overflow when `seconds' is huge. This assumes that + * the maximum value for a time_t is >= INT_MAX. + */ + if (seconds > INT_MAX) + return (seconds - INT_MAX + __sleep(INT_MAX)); + + time_to_sleep.tv_sec = seconds; + time_to_sleep.tv_nsec = 0; + if (INTERPOS_SYS(nanosleep, &time_to_sleep, &time_remaining) != -1) + return (0); + if (errno != EINTR) + return (seconds); /* best guess */ + return (time_remaining.tv_sec + + (time_remaining.tv_nsec != 0)); /* round up */ +} + +__weak_reference(__sleep, sleep); +__weak_reference(__sleep, _sleep); diff --git a/lib/libc/gen/srand48.c b/lib/libc/gen/srand48.c new file mode 100644 index 000000000000..4b82ece72db8 --- /dev/null +++ b/lib/libc/gen/srand48.c @@ -0,0 +1,23 @@ +/* + * Copyright (c) 1993 Martin Birgmeier + * All rights reserved. + * + * You may redistribute unmodified or modified versions of this source + * code provided that the above copyright notice and this and the + * following conditions are retained. + * + * This software is provided ``as is'', and comes with no warranties + * of any kind. I shall in no event be liable for anything that happens + * to anyone/anything when using this software. + */ + +#include "rand48.h" + +void +srand48(long seed) +{ + _rand48_seed = TOUINT48(RAND48_SEED_0, (unsigned short)seed, + (unsigned short)(seed >> 16)); + _rand48_mult = RAND48_MULT; + _rand48_add = RAND48_ADD; +} diff --git a/lib/libc/gen/statvfs.3 b/lib/libc/gen/statvfs.3 new file mode 100644 index 000000000000..e88f01eeeb26 --- /dev/null +++ b/lib/libc/gen/statvfs.3 @@ -0,0 +1,185 @@ +.\" +.\" Copyright 2002 Massachusetts Institute of Technology +.\" +.\" Permission to use, copy, modify, and distribute this software and +.\" its documentation for any purpose and without fee is hereby +.\" granted, provided that both the above copyright notice and this +.\" permission notice appear in all copies, that both the above +.\" copyright notice and this permission notice appear in all +.\" supporting documentation, and that the name of M.I.T. not be used +.\" in advertising or publicity pertaining to distribution of the +.\" software without specific, written prior permission. M.I.T. makes +.\" no representations about the suitability of this software for any +.\" purpose. It is provided "as is" without express or implied +.\" warranty. +.\" +.\" THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS +.\" ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, +.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT +.\" SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 13, 2002 +.Dt STATVFS 3 +.Os +.Sh NAME +.Nm statvfs , +.Nm fstatvfs +.Nd retrieve file system information +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/statvfs.h +.Ft int +.Fn statvfs "const char * restrict path" "struct statvfs * restrict buf" +.Ft int +.Fn fstatvfs "int fd" "struct statvfs *buf" +.Sh DESCRIPTION +The +.Fn statvfs +and +.Fn fstatvfs +functions fill the structure pointed to by +.Fa buf +with garbage. +This garbage will occasionally bear resemblance to file system +statistics, but portable applications must not depend on this. +Applications must pass a pathname or file descriptor which refers to a +file on the file system in which they are interested. +.Pp +The +.Vt statvfs +structure contains the following members: +.Bl -tag -offset indent -width ".Va f_namemax" +.It Va f_namemax +The maximum length in bytes of a file name on this file system. +Applications should use +.Xr pathconf 2 +instead. +.It Va f_fsid +Not meaningful in this implementation. +.It Va f_frsize +The size in bytes of the minimum unit of allocation on this +file system. +(This corresponds to the +.Va f_bsize +member of +.Vt "struct statfs" . ) +.It Va f_bsize +The preferred length of I/O requests for files on this file system. +(Corresponds to the +.Va f_iosize +member of +.Vt "struct statfs" . ) +.It Va f_flag +Flags describing mount options for this file system; see below. +.El +.Pp +In addition, there are three members of type +.Vt fsfilcnt_t , +which represent counts of file serial numbers +.Em ( i.e. , +inodes); these are named +.Va f_files , f_favail , +and +.Va f_ffree , +and represent the number of file serial numbers which exist in total, +are available to unprivileged processes, and are available to +privileged processes, respectively. +Likewise, the members +.Va f_blocks , f_bavail , +and +.Va f_bfree +(all of type +.Vt fsblkcnt_t ) +represent the respective allocation-block counts. +.Pp +There are two flags defined for the +.Va f_flag +member: +.Bl -tag -offset indent -width ".Dv ST_NOSUID" +.It Dv ST_RDONLY +The file system is mounted read-only. +.It Dv ST_NOSUID +The semantics of the +.Dv S_ISUID +and +.Dv S_ISGID +file mode bits +are not supported by, or are disabled on, this file system. +.El +.Sh IMPLEMENTATION NOTES +The +.Fn statvfs +and +.Fn fstatvfs +functions are implemented as wrappers around the +.Fn statfs +and +.Fn fstatfs +functions, respectively. +Not all the information provided by those functions is made available +through this interface. +.Sh RETURN VALUES +.Rv -std statvfs fstatvfs +.Sh ERRORS +The +.Fn statvfs +and +.Fn fstatvfs +functions may fail for any of the reasons documented for +.Xr statfs 2 +or +.Xr fstatfs 2 +and +.Xr pathconf 2 +or +.Xr fpathconf 2 , +respectively. +In addition, +.Fn statvfs +and +.Fn fstatvfs +functions may also fail for the following reason: +.Bl -tag -width Er +.It Bq Er EOVERFLOW +One or more of the file system statistics has a value which cannot be +represented by the data types used in +.Vt "struct statvfs" . +.El +.Sh SEE ALSO +.Xr pathconf 2 , +.Xr statfs 2 +.Sh STANDARDS +The +.Fn statvfs +and +.Fn fstatvfs +functions conform to +.St -p1003.1-2001 . +As standardized, portable applications cannot depend on these functions +returning any valid information at all. +This implementation attempts to provide as much useful information as +is provided by the underlying file system, subject to the limitations +of the specified data types. +.Sh HISTORY +The +.Fn statvfs +and +.Fn fstatvfs +functions first appeared in +.Fx 5.0 . +.Sh AUTHORS +The +.Fn statvfs +and +.Fn fstatvfs +functions and this manual page were written by +.An Garrett Wollman Aq Mt wollman@FreeBSD.org . diff --git a/lib/libc/gen/statvfs.c b/lib/libc/gen/statvfs.c new file mode 100644 index 000000000000..94c61f0cd73d --- /dev/null +++ b/lib/libc/gen/statvfs.c @@ -0,0 +1,157 @@ +/* + * Copyright 2002 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF + * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/statvfs.h> + +#include <errno.h> +#include <limits.h> +#include <unistd.h> +#include "un-namespace.h" + +static int sfs2svfs(const struct statfs *from, struct statvfs *to); + +int +fstatvfs(int fd, struct statvfs *result) +{ + struct statfs sfs; + int rv; + long pcval; + + rv = _fstatfs(fd, &sfs); + if (rv != 0) + return (rv); + + rv = sfs2svfs(&sfs, result); + if (rv != 0) + return (rv); + + /* + * Whether pathconf's -1 return means error or unlimited does not + * make any difference in this best-effort implementation. + */ + pcval = _fpathconf(fd, _PC_NAME_MAX); + if (pcval == -1) + result->f_namemax = ~0UL; + else + result->f_namemax = (unsigned long)pcval; + return (0); +} + +int +statvfs(const char * __restrict path, struct statvfs * __restrict result) +{ + struct statfs sfs; + int rv; + long pcval; + + rv = statfs(path, &sfs); + if (rv != 0) + return (rv); + + sfs2svfs(&sfs, result); + + /* + * Whether pathconf's -1 return means error or unlimited does not + * make any difference in this best-effort implementation. + */ + pcval = pathconf(path, _PC_NAME_MAX); + if (pcval == -1) + result->f_namemax = ~0UL; + else + result->f_namemax = (unsigned long)pcval; + return (0); +} + +static int +sfs2svfs(const struct statfs *from, struct statvfs *to) +{ + static const struct statvfs zvfs; + + *to = zvfs; + + if (from->f_flags & MNT_RDONLY) + to->f_flag |= ST_RDONLY; + if (from->f_flags & MNT_NOSUID) + to->f_flag |= ST_NOSUID; + + /* XXX should we clamp negative values? */ +#define COPY(field) \ + do { \ + to->field = from->field; \ + if (from->field != to->field) { \ + errno = EOVERFLOW; \ + return (-1); \ + } \ + } while(0) + + COPY(f_bavail); + COPY(f_bfree); + COPY(f_blocks); + COPY(f_ffree); + COPY(f_files); + to->f_bsize = from->f_iosize; + to->f_frsize = from->f_bsize; + to->f_favail = to->f_ffree; + return (0); +} + +#ifdef MAIN +#include <err.h> +#include <stdint.h> +#include <stdio.h> + +int +main(int argc, char **argv) +{ + struct statvfs buf; + + if (statvfs(argv[1], &buf) < 0) + err(1, "statvfs"); + +#define SHOW(field) \ + printf(#field ": %ju\n", (uintmax_t)buf.field) + + SHOW(f_bavail); + SHOW(f_bfree); + SHOW(f_blocks); + SHOW(f_favail); + SHOW(f_ffree); + SHOW(f_files); + SHOW(f_bsize); + SHOW(f_frsize); + SHOW(f_namemax); + printf("f_flag: %lx\n", (unsigned long)buf.f_flag); + + return 0; +} + +#endif /* MAIN */ diff --git a/lib/libc/gen/stringlist.3 b/lib/libc/gen/stringlist.3 new file mode 100644 index 000000000000..5e116f636281 --- /dev/null +++ b/lib/libc/gen/stringlist.3 @@ -0,0 +1,125 @@ +.\" $NetBSD: stringlist.3,v 1.5 1999/03/22 19:44:46 garbled Exp $ +.\" +.\" Copyright (c) 1997, 1999 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This file was contributed to The NetBSD Foundation by Luke Mewburn. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd November 28, 1999 +.Dt STRINGLIST 3 +.Os +.Sh NAME +.Nm stringlist , +.Nm sl_init , +.Nm sl_add , +.Nm sl_free , +.Nm sl_find +.Nd stringlist manipulation functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In stringlist.h +.Ft StringList * +.Fn sl_init +.Ft int +.Fn sl_add "StringList *sl" "char *item" +.Ft void +.Fn sl_free "StringList *sl" "int freeall" +.Ft char * +.Fn sl_find "StringList *sl" "const char *item" +.Sh DESCRIPTION +The +.Nm +functions manipulate stringlists, which are lists of +strings that extend automatically if necessary. +.Pp +The +.Vt StringList +structure has the following definition: +.Bd -literal -offset indent +typedef struct _stringlist { + char **sl_str; + size_t sl_max; + size_t sl_cur; +} StringList; +.Ed +.Bl -tag -width "sl_str" -offset indent +.It Va sl_str +a pointer to the base of the array containing the list. +.It Va sl_max +the size of +.Va sl_str . +.It Va sl_cur +the offset in +.Va sl_str +of the current element. +.El +.Pp +The following stringlist manipulation functions are available: +.Bl -tag -width "sl_init()" +.It Fn sl_init +Create a stringlist. +Returns a pointer to a +.Vt StringList , +or +.Dv NULL +in case of failure. +.It Fn sl_free +Releases memory occupied by +.Fa sl +and the +.Fa sl->sl_str +array. +If +.Fa freeall +is non-zero, then each of the items within +.Fa sl->sl_str +is released as well. +.It Fn sl_add +Add +.Fa item +to +.Fa sl->sl_str +at +.Fa sl->sl_cur , +extending the size of +.Fa sl->sl_str . +Returns zero upon success, \-1 upon failure. +.It Fn sl_find +Find +.Fa item +in +.Fa sl , +returning NULL if it is not found. +.El +.Sh SEE ALSO +.Xr free 3 , +.Xr malloc 3 +.Sh HISTORY +The +.Nm +functions appeared in +.Fx 2.2.6 +and +.Nx 1.3 . diff --git a/lib/libc/gen/stringlist.c b/lib/libc/gen/stringlist.c new file mode 100644 index 000000000000..5f333f3807aa --- /dev/null +++ b/lib/libc/gen/stringlist.c @@ -0,0 +1,112 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 1994 Christos Zoulas + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: stringlist.c,v 1.2 1997/01/17 07:26:20 lukem Exp $"); +#include "namespace.h" +#include <stdio.h> +#include <string.h> +#include <err.h> +#include <stdlib.h> +#include <stringlist.h> +#include "un-namespace.h" + +#define _SL_CHUNKSIZE 20 + +/* + * sl_init(): Initialize a string list + */ +StringList * +sl_init(void) +{ + StringList *sl; + + sl = malloc(sizeof(StringList)); + if (sl == NULL) + _err(1, "stringlist: %m"); + + sl->sl_cur = 0; + sl->sl_max = _SL_CHUNKSIZE; + sl->sl_str = malloc(sl->sl_max * sizeof(char *)); + if (sl->sl_str == NULL) + _err(1, "stringlist: %m"); + return sl; +} + + +/* + * sl_add(): Add an item to the string list + */ +int +sl_add(StringList *sl, char *name) +{ + if (sl->sl_cur == sl->sl_max - 1) { + sl->sl_max += _SL_CHUNKSIZE; + sl->sl_str = reallocf(sl->sl_str, sl->sl_max * sizeof(char *)); + if (sl->sl_str == NULL) + return (-1); + } + sl->sl_str[sl->sl_cur++] = name; + return (0); +} + + +/* + * sl_free(): Free a stringlist + */ +void +sl_free(StringList *sl, int all) +{ + size_t i; + + if (sl == NULL) + return; + if (sl->sl_str) { + if (all) + for (i = 0; i < sl->sl_cur; i++) + free(sl->sl_str[i]); + free(sl->sl_str); + } + free(sl); +} + + +/* + * sl_find(): Find a name in the string list + */ +char * +sl_find(StringList *sl, const char *name) +{ + size_t i; + + for (i = 0; i < sl->sl_cur; i++) + if (strcmp(sl->sl_str[i], name) == 0) + return sl->sl_str[i]; + + return NULL; +} diff --git a/lib/libc/gen/strtofflags.3 b/lib/libc/gen/strtofflags.3 new file mode 100644 index 000000000000..0cf996275480 --- /dev/null +++ b/lib/libc/gen/strtofflags.3 @@ -0,0 +1,92 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 1, 2000 +.Dt STRTOFFLAGS 3 +.Os +.Sh NAME +.Nm fflagstostr , +.Nm strtofflags +.Nd convert between file flag bits and their string names +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft char * +.Fn fflagstostr "u_long flags" +.Ft int +.Fn strtofflags "char **stringp" "u_long *setp" "u_long *clrp" +.Sh DESCRIPTION +The +.Fn fflagstostr +function returns a comma separated string of the file flags represented by +.Fa flags . +If no flags are set a zero length string is returned. +.Pp +If memory cannot be allocated for the return value, +.Fn fflagstostr +returns +.Dv NULL . +.Pp +The value returned from +.Fn fflagstostr +is obtained from +.Fn malloc +and should be returned to the system with +.Fn free +when the program is done with it. +.Pp +The +.Fn strtofflags +function takes a string of file flags, as described in +.Xr chflags 1 , +parses it, and returns the 'set' flags and 'clear' flags +such as would be given as arguments to +.Xr chflags 2 . +On success +.Fn strtofflags +returns 0, otherwise it returns non-zero and +.Fa stringp +is left pointing to the offending token. +.Sh ERRORS +The +.Fn fflagstostr +function +may fail and set errno for any of the errors specified for the library +routine +.Xr malloc 3 . +.Sh SEE ALSO +.Xr chflags 1 , +.Xr chflags 2 , +.Xr malloc 3 +.Sh HISTORY +The +.Fn fflagstostr +and +.Fn strtofflags +functions first appeared in +.Fx 4.0 . diff --git a/lib/libc/gen/strtofflags.c b/lib/libc/gen/strtofflags.c new file mode 100644 index 000000000000..73b4db54ccdd --- /dev/null +++ b/lib/libc/gen/strtofflags.c @@ -0,0 +1,165 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#define longestflaglen 12 +static struct { + char name[longestflaglen + 1]; + char invert; + u_long flag; +} const mapping[] = { + /* shorter names per flag first, all prefixed by "no" */ + { "nosappnd", 0, SF_APPEND }, + { "nosappend", 0, SF_APPEND }, + { "noarch", 0, SF_ARCHIVED }, + { "noarchived", 0, SF_ARCHIVED }, + { "noschg", 0, SF_IMMUTABLE }, + { "noschange", 0, SF_IMMUTABLE }, + { "nosimmutable", 0, SF_IMMUTABLE }, + { "nosunlnk", 0, SF_NOUNLINK }, + { "nosunlink", 0, SF_NOUNLINK }, +#ifdef SF_SNAPSHOT + { "nosnapshot", 0, SF_SNAPSHOT }, +#endif + { "nouappnd", 0, UF_APPEND }, + { "nouappend", 0, UF_APPEND }, + { "nouarch", 0, UF_ARCHIVE }, + { "nouarchive", 0, UF_ARCHIVE }, + { "nohidden", 0, UF_HIDDEN }, + { "nouhidden", 0, UF_HIDDEN }, + { "nouchg", 0, UF_IMMUTABLE }, + { "nouchange", 0, UF_IMMUTABLE }, + { "nouimmutable", 0, UF_IMMUTABLE }, + { "nodump", 1, UF_NODUMP }, + { "nouunlnk", 0, UF_NOUNLINK }, + { "nouunlink", 0, UF_NOUNLINK }, + { "nooffline", 0, UF_OFFLINE }, + { "nouoffline", 0, UF_OFFLINE }, + { "noopaque", 0, UF_OPAQUE }, + { "nordonly", 0, UF_READONLY }, + { "nourdonly", 0, UF_READONLY }, + { "noreadonly", 0, UF_READONLY }, + { "noureadonly", 0, UF_READONLY }, + { "noreparse", 0, UF_REPARSE }, + { "noureparse", 0, UF_REPARSE }, + { "nosparse", 0, UF_SPARSE }, + { "nousparse", 0, UF_SPARSE }, + { "nosystem", 0, UF_SYSTEM }, + { "nousystem", 0, UF_SYSTEM } +}; +#define nmappings (sizeof(mapping) / sizeof(mapping[0])) + +/* + * fflagstostr -- + * Convert file flags to a comma-separated string. If no flags + * are set, return the empty string. + */ +char * +fflagstostr(u_long flags) +{ + char *string; + const char *sp; + char *dp; + u_long setflags; + u_int i; + + if ((string = (char *)malloc(nmappings * (longestflaglen + 1))) == NULL) + return (NULL); + + setflags = flags; + dp = string; + for (i = 0; i < nmappings; i++) { + if (setflags & mapping[i].flag) { + if (dp > string) + *dp++ = ','; + for (sp = mapping[i].invert ? mapping[i].name : + mapping[i].name + 2; *sp; *dp++ = *sp++) ; + setflags &= ~mapping[i].flag; + } + } + *dp = '\0'; + return (string); +} + +/* + * strtofflags -- + * Take string of arguments and return file flags. Return 0 on + * success, 1 on failure. On failure, stringp is set to point + * to the offending token. + */ +int +strtofflags(char **stringp, u_long *setp, u_long *clrp) +{ + char *string, *p; + int i; + + if (setp) + *setp = 0; + if (clrp) + *clrp = 0; + string = *stringp; + while ((p = strsep(&string, "\t ,")) != NULL) { + *stringp = p; + if (*p == '\0') + continue; + for (i = 0; i < nmappings; i++) { + if (strcmp(p, mapping[i].name + 2) == 0) { + if (mapping[i].invert) { + if (clrp) + *clrp |= mapping[i].flag; + } else { + if (setp) + *setp |= mapping[i].flag; + } + break; + } else if (strcmp(p, mapping[i].name) == 0) { + if (mapping[i].invert) { + if (setp) + *setp |= mapping[i].flag; + } else { + if (clrp) + *clrp |= mapping[i].flag; + } + break; + } + } + if (i == nmappings) + return 1; + } + return 0; +} diff --git a/lib/libc/gen/sysconf.3 b/lib/libc/gen/sysconf.3 new file mode 100644 index 000000000000..e38357b898a7 --- /dev/null +++ b/lib/libc/gen/sysconf.3 @@ -0,0 +1,273 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 26, 2013 +.Dt SYSCONF 3 +.Os +.Sh NAME +.Nm sysconf +.Nd get configurable system variables +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft long +.Fn sysconf "int name" +.Sh DESCRIPTION +This interface is defined by +.St -p1003.1-88 . +A far more complete interface is available using +.Xr sysctl 3 . +.Pp +The +.Fn sysconf +function provides a method for applications to determine the current +value of a configurable system limit or option variable. +The +.Fa name +argument specifies the system variable to be queried. +Symbolic constants for each name value are found in the include file +.In unistd.h . +Shell programmers who need access to these parameters should use the +.Xr getconf 1 +utility. +.Pp +The available values are as follows: +.Bl -tag -width 6n +.It Li _SC_ARG_MAX +The maximum bytes of argument to +.Xr execve 2 . +.It Li _SC_CHILD_MAX +The maximum number of simultaneous processes per user id. +.It Li _SC_CLK_TCK +The frequency of the statistics clock in ticks per second. +.It Li _SC_IOV_MAX +The maximum number of elements in the I/O vector used by +.Xr readv 2 , +.Xr writev 2 , +.Xr recvmsg 2 , +and +.Xr sendmsg 2 . +.It Li _SC_NGROUPS_MAX +The maximum number of supplemental groups. +.It Li _SC_NPROCESSORS_CONF +The number of processors configured. +.It Li _SC_NPROCESSORS_ONLN +The number of processors currently online. +.It Li _SC_OPEN_MAX +One more than the maximum value the system may assign to a new file descriptor. +.It Li _SC_PAGESIZE +The size of a system page in bytes. +.It Li _SC_PAGE_SIZE +Equivalent to +.Li _SC_PAGESIZE . +.It Li _SC_STREAM_MAX +The minimum maximum number of streams that a process may have open +at any one time. +.It Li _SC_TZNAME_MAX +The minimum maximum number of types supported for the name of a +timezone. +.It Li _SC_JOB_CONTROL +Return 1 if job control is available on this system, otherwise \-1. +.It Li _SC_SAVED_IDS +Returns 1 if saved set-group and saved set-user ID is available, +otherwise \-1. +.It Li _SC_VERSION +The version of +.St -p1003.1 +with which the system +attempts to comply. +.It Li _SC_BC_BASE_MAX +The maximum ibase/obase values in the +.Xr bc 1 +utility. +.It Li _SC_BC_DIM_MAX +The maximum array size in the +.Xr bc 1 +utility. +.It Li _SC_BC_SCALE_MAX +The maximum scale value in the +.Xr bc 1 +utility. +.It Li _SC_BC_STRING_MAX +The maximum string length in the +.Xr bc 1 +utility. +.It Li _SC_COLL_WEIGHTS_MAX +The maximum number of weights that can be assigned to any entry of +the LC_COLLATE order keyword in the locale definition file. +.It Li _SC_EXPR_NEST_MAX +The maximum number of expressions that can be nested within +parenthesis by the +.Xr expr 1 +utility. +.It Li _SC_LINE_MAX +The maximum length in bytes of a text-processing utility's input +line. +.It Li _SC_RE_DUP_MAX +The maximum number of repeated occurrences of a regular expression +permitted when using interval notation. +.It Li _SC_2_VERSION +The version of +.St -p1003.2 +with which the system attempts to comply. +.It Li _SC_2_C_BIND +Return 1 if the system's C-language development facilities support the +C-Language Bindings Option, otherwise \-1. +.It Li _SC_2_C_DEV +Return 1 if the system supports the C-Language Development Utilities Option, +otherwise \-1. +.It Li _SC_2_CHAR_TERM +Return 1 if the system supports at least one terminal type capable of +all operations described in +.St -p1003.2 , +otherwise \-1. +.It Li _SC_2_FORT_DEV +Return 1 if the system supports the FORTRAN Development Utilities Option, +otherwise \-1. +.It Li _SC_2_FORT_RUN +Return 1 if the system supports the FORTRAN Runtime Utilities Option, +otherwise \-1. +.It Li _SC_2_LOCALEDEF +Return 1 if the system supports the creation of locales, otherwise \-1. +.It Li _SC_2_SW_DEV +Return 1 if the system supports the Software Development Utilities Option, +otherwise \-1. +.It Li _SC_2_UPE +Return 1 if the system supports the User Portability Utilities Option, +otherwise \-1. +.It Li _SC_AIO_LISTIO_MAX +Maximum number of I/O operations in a single list I/O call supported. +.It Li _SC_AIO_MAX +Maximum number of outstanding asynchronous I/O operations supported. +.It Li _SC_AIO_PRIO_DELTA_MAX +The maximum amount by which a process can decrease its asynchronous I/O +priority level from its own scheduling priority. +.It Li _SC_DELAYTIMER_MAX +Maximum number of timer expiration overruns. +.It Li _SC_MQ_OPEN_MAX +The maximum number of open message queue descriptors a process may hold. +.It Li _SC_RTSIG_MAX +Maximum number of realtime signals reserved for application use. +.It Li _SC_SEM_NSEMS_MAX +Maximum number of semaphores that a process may have. +.It Li _SC_SEM_VALUE_MAX +The maximum value a semaphore may have. +.It Li _SC_SIGQUEUE_MAX +Maximum number of queued signals that a process may send and have pending at +the receiver(s) at any time. +.It Li _SC_TIMER_MAX +Maximum number of timers per process supported. +.It Li _SC_GETGR_R_SIZE_MAX +Suggested initial value for the size of the group entry buffer. +.It Li _SC_GETPW_R_SIZE_MAX +Suggested initial value for the size of the password entry buffer. +.It Li _SC_HOST_NAME_MAX +Maximum length of a host name (not including the terminating null) as +returned from the +.Fn gethostname +function. +.It Li _SC_LOGIN_NAME_MAX +Maximum length of a login name. +.It Li _SC_THREAD_STACK_MIN +Minimum size in bytes of thread stack storage. +.It Li _SC_THREAD_THREADS_MAX +Maximum number of threads that can be created per process. +.It Li _SC_TTY_NAME_MAX +Maximum length of terminal device name. +.It Li _SC_SYMLOOP_MAX +Maximum number of symbolic links that can be reliably traversed in the +resolution of a pathname in the absence of a loop. +.It Li _SC_ATEXIT_MAX +Maximum number of functions that may be registered with +.Fn atexit . +.It Li _SC_XOPEN_VERSION +An integer value greater than or equal to 4, +indicating the version of the X/Open Portability Guide to which this +system conforms. +.It Li _SC_XOPEN_XCU_VERSION +An integer value indicating the version of the XCU Specification to which +this system conforms. +.El +.Pp +These values also exist, but may not be standard: +.Bl -tag -width 6n +.It Li _SC_CPUSET_SIZE +Size of the kernel cpuset. +.It Li _SC_PHYS_PAGES +The number of pages of physical memory. +Note that it is possible that the product of this value and the value of +.Li _SC_PAGESIZE +will overflow a +.Vt long +in some configurations on a 32bit machine. +.El +.Sh RETURN VALUES +If the call to +.Fn sysconf +is not successful, \-1 is returned and +.Va errno +is set appropriately. +Otherwise, if the variable is associated with functionality that is not +supported, \-1 is returned and +.Va errno +is not modified. +Otherwise, the current variable value is returned. +.Sh ERRORS +The +.Fn sysconf +function may fail and set +.Va errno +for any of the errors specified for the library function +.Xr sysctl 3 . +In addition, the following error may be reported: +.Bl -tag -width Er +.It Bq Er EINVAL +The value of the +.Fa name +argument is invalid. +.El +.Sh SEE ALSO +.Xr getconf 1 , +.Xr pathconf 2 , +.Xr confstr 3 , +.Xr sysctl 3 +.Sh STANDARDS +Except for the fact that values returned by +.Fn sysconf +may change over the lifetime of the calling process, +this function conforms to +.St -p1003.1-88 . +.Sh HISTORY +The +.Fn sysconf +function first appeared in +.Bx 4.4 . +.Sh BUGS +The value for _SC_STREAM_MAX is a minimum maximum, and required to be +the same as ANSI C's FOPEN_MAX, so the returned value is a ridiculously +small and misleading number. diff --git a/lib/libc/gen/sysconf.c b/lib/libc/gen/sysconf.c new file mode 100644 index 000000000000..b5b732eed05d --- /dev/null +++ b/lib/libc/gen/sysconf.c @@ -0,0 +1,619 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Sean Eric Fagan of Cygnus Support. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/exterrvar.h> +#include <sys/time.h> +#include <sys/sysctl.h> +#include <sys/resource.h> +#include <sys/socket.h> + +#include <elf.h> +#include <errno.h> +#include <limits.h> +#include <paths.h> +#include <pthread.h> /* we just need the limits */ +#include <semaphore.h> +#include <time.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "../stdlib/atexit.h" +#include "tzdir.h" /* from ../../../contrib/tzcode */ +#include "libc_private.h" + +#define _PATH_ZONEINFO TZDIR /* from tzfile.h */ + +/* + * sysconf -- + * get configurable system variables. + * + * XXX + * POSIX 1003.1 (ISO/IEC 9945-1, 4.8.1.3) states that the variable values + * not change during the lifetime of the calling process. This would seem + * to require that any change to system limits kill all running processes. + * A workaround might be to cache the values when they are first retrieved + * and then simply return the cached value on subsequent calls. This is + * less useful than returning up-to-date values, however. + */ +long +sysconf(int name) +{ + struct rlimit rl; + size_t len; + int mib[2], sverrno, value; + long lvalue, defaultresult; + const char *path; + + defaultresult = -1; + + switch (name) { + case _SC_ARG_MAX: + mib[0] = CTL_KERN; + mib[1] = KERN_ARGMAX; + break; + case _SC_CHILD_MAX: + if (getrlimit(RLIMIT_NPROC, &rl) != 0) + return (-1); + if (rl.rlim_cur == RLIM_INFINITY) + return (-1); + if (rl.rlim_cur > LONG_MAX) { + errno = EOVERFLOW; + return (-1); + } + return ((long)rl.rlim_cur); + case _SC_CLK_TCK: + return (CLK_TCK); + case _SC_NGROUPS_MAX: + mib[0] = CTL_KERN; + mib[1] = KERN_NGROUPS; + break; + case _SC_OPEN_MAX: + if (getrlimit(RLIMIT_NOFILE, &rl) != 0) + return (-1); + if (rl.rlim_cur == RLIM_INFINITY) + return (-1); + if (rl.rlim_cur > LONG_MAX) { + errno = EOVERFLOW; + return (-1); + } + return ((long)rl.rlim_cur); + case _SC_STREAM_MAX: + if (getrlimit(RLIMIT_NOFILE, &rl) != 0) + return (-1); + if (rl.rlim_cur == RLIM_INFINITY) + return (-1); + if (rl.rlim_cur > LONG_MAX) { + errno = EOVERFLOW; + return (-1); + } + /* + * struct __sFILE currently has a limitation that + * file descriptors must fit in a signed short. + * This doesn't precisely capture the letter of POSIX + * but approximates the spirit. + */ + if (rl.rlim_cur > SHRT_MAX) + return (SHRT_MAX); + + return ((long)rl.rlim_cur); + case _SC_JOB_CONTROL: + return (_POSIX_JOB_CONTROL); + case _SC_SAVED_IDS: + /* XXX - must be 1 */ + mib[0] = CTL_KERN; + mib[1] = KERN_SAVED_IDS; + goto yesno; + case _SC_VERSION: + mib[0] = CTL_KERN; + mib[1] = KERN_POSIX1; + break; + case _SC_BC_BASE_MAX: + return (BC_BASE_MAX); + case _SC_BC_DIM_MAX: + return (BC_DIM_MAX); + case _SC_BC_SCALE_MAX: + return (BC_SCALE_MAX); + case _SC_BC_STRING_MAX: + return (BC_STRING_MAX); + case _SC_COLL_WEIGHTS_MAX: + return (COLL_WEIGHTS_MAX); + case _SC_EXPR_NEST_MAX: + return (EXPR_NEST_MAX); + case _SC_LINE_MAX: + return (LINE_MAX); + case _SC_RE_DUP_MAX: + return (RE_DUP_MAX); + case _SC_2_VERSION: + /* + * This is something of a lie, but it would be silly at + * this point to try to deduce this from the contents + * of the filesystem. + */ + return (_POSIX2_VERSION); + case _SC_2_C_BIND: + return (_POSIX2_C_BIND); + case _SC_2_C_DEV: + return (_POSIX2_C_DEV); + case _SC_2_CHAR_TERM: + return (_POSIX2_CHAR_TERM); + case _SC_2_FORT_DEV: + return (_POSIX2_FORT_DEV); + case _SC_2_FORT_RUN: + return (_POSIX2_FORT_RUN); + case _SC_2_LOCALEDEF: + return (_POSIX2_LOCALEDEF); + case _SC_2_SW_DEV: + return (_POSIX2_SW_DEV); + case _SC_2_UPE: + return (_POSIX2_UPE); + case _SC_TZNAME_MAX: + path = _PATH_ZONEINFO; +do_NAME_MAX: + sverrno = errno; + errno = 0; + lvalue = pathconf(path, _PC_NAME_MAX); + if (lvalue == -1 && errno != 0) + return (-1); + errno = sverrno; + return (lvalue); + + case _SC_ASYNCHRONOUS_IO: +#if _POSIX_ASYNCHRONOUS_IO == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_ASYNCHRONOUS_IO; + break; +#else + return (_POSIX_ASYNCHRONOUS_IO); +#endif + case _SC_MAPPED_FILES: + return (_POSIX_MAPPED_FILES); + case _SC_MEMLOCK: + return (_POSIX_MEMLOCK); + case _SC_MEMLOCK_RANGE: + return (_POSIX_MEMLOCK_RANGE); + case _SC_MEMORY_PROTECTION: + return (_POSIX_MEMORY_PROTECTION); + case _SC_MESSAGE_PASSING: +#if _POSIX_MESSAGE_PASSING == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_MESSAGE_PASSING; + goto yesno; +#else + return (_POSIX_MESSAGE_PASSING); +#endif + case _SC_PRIORITIZED_IO: +#if _POSIX_PRIORITIZED_IO == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_PRIORITIZED_IO; + goto yesno; +#else + return (_POSIX_PRIORITIZED_IO); +#endif + case _SC_PRIORITY_SCHEDULING: +#if _POSIX_PRIORITY_SCHEDULING == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_PRIORITY_SCHEDULING; + goto yesno; +#else + return (_POSIX_PRIORITY_SCHEDULING); +#endif + case _SC_REALTIME_SIGNALS: +#if _POSIX_REALTIME_SIGNALS == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_REALTIME_SIGNALS; + goto yesno; +#else + return (_POSIX_REALTIME_SIGNALS); +#endif + case _SC_SEMAPHORES: +#if _POSIX_SEMAPHORES == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_SEMAPHORES; + goto yesno; +#else + return (_POSIX_SEMAPHORES); +#endif + case _SC_FSYNC: + return (_POSIX_FSYNC); + + case _SC_SHARED_MEMORY_OBJECTS: + return (_POSIX_SHARED_MEMORY_OBJECTS); + case _SC_SYNCHRONIZED_IO: +#if _POSIX_SYNCHRONIZED_IO == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_SYNCHRONIZED_IO; + goto yesno; +#else + return (_POSIX_SYNCHRONIZED_IO); +#endif + case _SC_TIMERS: +#if _POSIX_TIMERS == 0 + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_TIMERS; + goto yesno; +#else + return (_POSIX_TIMERS); +#endif + case _SC_AIO_LISTIO_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_AIO_LISTIO_MAX; + break; + case _SC_AIO_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_AIO_MAX; + break; + case _SC_AIO_PRIO_DELTA_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_AIO_PRIO_DELTA_MAX; + break; + case _SC_DELAYTIMER_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_DELAYTIMER_MAX; + goto yesno; + case _SC_MQ_OPEN_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_MQ_OPEN_MAX; + goto yesno; + case _SC_NSIG: + return (_SIG_MAXSIG); + case _SC_PAGESIZE: + return (getpagesize()); + case _SC_RTSIG_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_RTSIG_MAX; + goto yesno; + case _SC_SEM_NSEMS_MAX: + return (-1); + case _SC_SEM_VALUE_MAX: + return (SEM_VALUE_MAX); + case _SC_SIGQUEUE_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_SIGQUEUE_MAX; + goto yesno; + case _SC_TIMER_MAX: + mib[0] = CTL_P1003_1B; + mib[1] = CTL_P1003_1B_TIMER_MAX; +yesno: + len = sizeof(value); + if (sysctl(mib, 2, &value, &len, NULL, 0) == -1) + return (-1); + if (value == 0) + return (defaultresult); + return ((long)value); + + case _SC_2_PBS: + case _SC_2_PBS_ACCOUNTING: + case _SC_2_PBS_CHECKPOINT: + case _SC_2_PBS_LOCATE: + case _SC_2_PBS_MESSAGE: + case _SC_2_PBS_TRACK: +#if _POSIX2_PBS == 0 +#error "don't know how to determine _SC_2_PBS" + /* + * This probably requires digging through the filesystem + * to see if the appropriate package has been installed. + * Since we don't currently support this option at all, + * it's not worth the effort to write the code now. + * Figuring out which of the sub-options are supported + * would be even more difficult, so it's probably easier + * to always say ``no''. + */ +#else + return (_POSIX2_PBS); +#endif + case _SC_ADVISORY_INFO: +#if _POSIX_ADVISORY_INFO == 0 +#error "_POSIX_ADVISORY_INFO" +#else + return (_POSIX_ADVISORY_INFO); +#endif + case _SC_BARRIERS: +#if _POSIX_BARRIERS == 0 +#error "_POSIX_BARRIERS" +#else + return (_POSIX_BARRIERS); +#endif + case _SC_CLOCK_SELECTION: +#if _POSIX_CLOCK_SELECTION == 0 +#error "_POSIX_CLOCK_SELECTION" +#else + return (_POSIX_CLOCK_SELECTION); +#endif + case _SC_CPUTIME: + return (_POSIX_CPUTIME); +#ifdef notdef + case _SC_FILE_LOCKING: + /* + * XXX - The standard doesn't tell us how to define + * _POSIX_FILE_LOCKING, so we can't answer this one. + */ +#endif + + /* + * SUSv4tc1 says the following about _SC_GETGR_R_SIZE_MAX and + * _SC_GETPW_R_SIZE_MAX: + * Note that sysconf(_SC_GETGR_R_SIZE_MAX) may return -1 if + * there is no hard limit on the size of the buffer needed to + * store all the groups returned. + */ + case _SC_GETGR_R_SIZE_MAX: + case _SC_GETPW_R_SIZE_MAX: + return (-1); + case _SC_HOST_NAME_MAX: + return (MAXHOSTNAMELEN - 1); /* does not include \0 */ + case _SC_LOGIN_NAME_MAX: + return (MAXLOGNAME); + case _SC_MONOTONIC_CLOCK: +#if _POSIX_MONOTONIC_CLOCK == 0 +#error "_POSIX_MONOTONIC_CLOCK" +#else + return (_POSIX_MONOTONIC_CLOCK); +#endif +#if _POSIX_MESSAGE_PASSING > -1 + case _SC_MQ_PRIO_MAX: + return (MQ_PRIO_MAX); +#endif + case _SC_READER_WRITER_LOCKS: + return (_POSIX_READER_WRITER_LOCKS); + case _SC_REGEXP: + return (_POSIX_REGEXP); + case _SC_SHELL: + return (_POSIX_SHELL); + case _SC_SPAWN: + return (_POSIX_SPAWN); + case _SC_SPIN_LOCKS: + return (_POSIX_SPIN_LOCKS); + case _SC_SPORADIC_SERVER: +#if _POSIX_SPORADIC_SERVER == 0 +#error "_POSIX_SPORADIC_SERVER" +#else + return (_POSIX_SPORADIC_SERVER); +#endif + case _SC_THREAD_ATTR_STACKADDR: + return (_POSIX_THREAD_ATTR_STACKADDR); + case _SC_THREAD_ATTR_STACKSIZE: + return (_POSIX_THREAD_ATTR_STACKSIZE); + case _SC_THREAD_CPUTIME: + return (_POSIX_THREAD_CPUTIME); + case _SC_THREAD_DESTRUCTOR_ITERATIONS: + return (PTHREAD_DESTRUCTOR_ITERATIONS); + case _SC_THREAD_KEYS_MAX: + return (PTHREAD_KEYS_MAX); + case _SC_THREAD_PRIO_INHERIT: + return (_POSIX_THREAD_PRIO_INHERIT); + case _SC_THREAD_PRIO_PROTECT: + return (_POSIX_THREAD_PRIO_PROTECT); + case _SC_THREAD_PRIORITY_SCHEDULING: + return (_POSIX_THREAD_PRIORITY_SCHEDULING); + case _SC_THREAD_PROCESS_SHARED: + return (_POSIX_THREAD_PROCESS_SHARED); + case _SC_THREAD_SAFE_FUNCTIONS: + return (_POSIX_THREAD_SAFE_FUNCTIONS); + case _SC_THREAD_STACK_MIN: + return (PTHREAD_STACK_MIN); + case _SC_THREAD_THREADS_MAX: + return (PTHREAD_THREADS_MAX); /* XXX wrong type! */ + case _SC_TIMEOUTS: + return (_POSIX_TIMEOUTS); + case _SC_THREADS: + return (_POSIX_THREADS); + case _SC_TRACE: +#if _POSIX_TRACE == 0 +#error "_POSIX_TRACE" + /* While you're implementing this, also do the ones below. */ +#else + return (_POSIX_TRACE); +#endif +#if _POSIX_TRACE > -1 + case _SC_TRACE_EVENT_FILTER: + return (_POSIX_TRACE_EVENT_FILTER); + case _SC_TRACE_INHERIT: + return (_POSIX_TRACE_INHERIT); + case _SC_TRACE_LOG: + return (_POSIX_TRACE_LOG); +#endif + case _SC_TTY_NAME_MAX: + path = _PATH_DEV; + goto do_NAME_MAX; + case _SC_TYPED_MEMORY_OBJECTS: +#if _POSIX_TYPED_MEMORY_OBJECTS == 0 +#error "_POSIX_TYPED_MEMORY_OBJECTS" +#else + return (_POSIX_TYPED_MEMORY_OBJECTS); +#endif + case _SC_V6_ILP32_OFF32: +#if _V6_ILP32_OFF32 == 0 + if (sizeof(int) * CHAR_BIT == 32 && + sizeof(int) == sizeof(long) && + sizeof(long) == sizeof(void *) && + sizeof(void *) == sizeof(off_t)) + return 1; + else + return -1; +#else + return (_V6_ILP32_OFF32); +#endif + case _SC_V6_ILP32_OFFBIG: +#if _V6_ILP32_OFFBIG == 0 + if (sizeof(int) * CHAR_BIT == 32 && + sizeof(int) == sizeof(long) && + sizeof(long) == sizeof(void *) && + sizeof(off_t) * CHAR_BIT >= 64) + return 1; + else + return -1; +#else + return (_V6_ILP32_OFFBIG); +#endif + case _SC_V6_LP64_OFF64: +#if _V6_LP64_OFF64 == 0 + if (sizeof(int) * CHAR_BIT == 32 && + sizeof(long) * CHAR_BIT == 64 && + sizeof(long) == sizeof(void *) && + sizeof(void *) == sizeof(off_t)) + return 1; + else + return -1; +#else + return (_V6_LP64_OFF64); +#endif + case _SC_V6_LPBIG_OFFBIG: +#if _V6_LPBIG_OFFBIG == 0 + if (sizeof(int) * CHAR_BIT >= 32 && + sizeof(long) * CHAR_BIT >= 64 && + sizeof(void *) * CHAR_BIT >= 64 && + sizeof(off_t) * CHAR_BIT >= 64) + return 1; + else + return -1; +#else + return (_V6_LPBIG_OFFBIG); +#endif + case _SC_ATEXIT_MAX: + return (ATEXIT_SIZE); + case _SC_IOV_MAX: + mib[0] = CTL_KERN; + mib[1] = KERN_IOV_MAX; + break; + case _SC_XOPEN_CRYPT: + return (_XOPEN_CRYPT); + case _SC_XOPEN_ENH_I18N: + return (_XOPEN_ENH_I18N); + case _SC_XOPEN_LEGACY: + return (_XOPEN_LEGACY); + case _SC_XOPEN_REALTIME: +#if _XOPEN_REALTIME == 0 + sverrno = errno; + value = sysconf(_SC_ASYNCHRONOUS_IO) > 0 && + sysconf(_SC_MEMLOCK) > 0 && + sysconf(_SC_MEMLOCK_RANGE) > 0 && + sysconf(_SC_MESSAGE_PASSING) > 0 && + sysconf(_SC_PRIORITY_SCHEDULING) > 0 && + sysconf(_SC_REALTIME_SIGNALS) > 0 && + sysconf(_SC_SEMAPHORES) > 0 && + sysconf(_SC_SHARED_MEMORY_OBJECTS) > 0 && + sysconf(_SC_SYNCHRONIZED_IO) > 0 && + sysconf(_SC_TIMERS) > 0; + errno = sverrno; + if (value) + return (200112L); + else + return (-1); +#else + return (_XOPEN_REALTIME); +#endif + case _SC_XOPEN_REALTIME_THREADS: +#if _XOPEN_REALTIME_THREADS == 0 +#error "_XOPEN_REALTIME_THREADS" +#else + return (_XOPEN_REALTIME_THREADS); +#endif + case _SC_XOPEN_SHM: + len = sizeof(lvalue); + sverrno = errno; + if (sysctlbyname("kern.ipc.shmmin", &lvalue, &len, NULL, + 0) == -1) { + errno = sverrno; + return (-1); + } + errno = sverrno; + return (1); + case _SC_XOPEN_STREAMS: + return (_XOPEN_STREAMS); + case _SC_XOPEN_UNIX: + return (_XOPEN_UNIX); +#ifdef _XOPEN_VERSION + case _SC_XOPEN_VERSION: + return (_XOPEN_VERSION); +#endif +#ifdef _XOPEN_XCU_VERSION + case _SC_XOPEN_XCU_VERSION: + return (_XOPEN_XCU_VERSION); +#endif + case _SC_SYMLOOP_MAX: + return (MAXSYMLINKS); + case _SC_RAW_SOCKETS: + return (_POSIX_RAW_SOCKETS); + case _SC_IPV6: +#if _POSIX_IPV6 == 0 + sverrno = errno; + value = _socket(PF_INET6, SOCK_CLOEXEC | SOCK_DGRAM, 0); + errno = sverrno; + if (value >= 0) { + _close(value); + return (200112L); + } else + return (0); +#else + return (_POSIX_IPV6); +#endif + + case _SC_NPROCESSORS_CONF: + case _SC_NPROCESSORS_ONLN: + if (_elf_aux_info(AT_NCPUS, &value, sizeof(value)) == 0) + return ((long)value); + mib[0] = CTL_HW; + mib[1] = HW_NCPU; + break; + +#ifdef _SC_PHYS_PAGES + case _SC_PHYS_PAGES: + len = sizeof(lvalue); + if (sysctlbyname("hw.availpages", &lvalue, &len, NULL, 0) == -1) + return (-1); + return (lvalue); +#endif + +#ifdef _SC_CPUSET_SIZE + case _SC_CPUSET_SIZE: + len = sizeof(value); + if (sysctlbyname("kern.sched.cpusetsize", &value, &len, NULL, + 0) == -1) + return (-1); + return ((long)value); +#endif + case _SC_UEXTERR_MAXLEN: + return (UEXTERROR_MAXLEN); + + default: + errno = EINVAL; + return (-1); + } + len = sizeof(value); + if (sysctl(mib, 2, &value, &len, NULL, 0) == -1) + value = -1; + return ((long)value); +} diff --git a/lib/libc/gen/sysctl.3 b/lib/libc/gen/sysctl.3 new file mode 100644 index 000000000000..ef897c653728 --- /dev/null +++ b/lib/libc/gen/sysctl.3 @@ -0,0 +1,964 @@ +.\" Copyright (c) 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 31, 2025 +.Dt SYSCTL 3 +.Os +.Sh NAME +.Nm sysctl , +.Nm sysctlbyname , +.Nm sysctlnametomib +.Nd get or set system information +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/sysctl.h +.Ft int +.Fn sysctl "const int *name" "u_int namelen" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen" +.Ft int +.Fn sysctlbyname "const char *name" "void *oldp" "size_t *oldlenp" "const void *newp" "size_t newlen" +.Ft int +.Fn sysctlnametomib "const char *name" "int *mibp" "size_t *sizep" +.Sh DESCRIPTION +The +.Fn sysctl +function retrieves system information and allows processes with +appropriate privileges to set system information. +The information available from +.Fn sysctl +consists of integers, strings, and tables. +Information may be retrieved and set from the command interface +using the +.Xr sysctl 8 +utility. +.Pp +Unless explicitly noted below, +.Fn sysctl +returns a consistent snapshot of the data requested. +Consistency is obtained by locking the destination +buffer into memory so that the data may be copied out without blocking. +Calls to +.Fn sysctl +are serialized to avoid deadlock. +.Pp +The state is described using a ``Management Information Base'' (MIB) +style name, listed in +.Fa name , +which is a +.Fa namelen +length array of integers. +.Pp +The +.Fn sysctlbyname +function accepts an ASCII representation of the name and internally +looks up the integer name vector. +Apart from that, it behaves the same +as the standard +.Fn sysctl +function. +.Pp +The information is copied into the buffer specified by +.Fa oldp . +The size of the buffer is given by the location specified by +.Fa oldlenp +before the call, +and that location gives the amount of data copied after a successful call +and after a call that returns with the error code +.Er ENOMEM . +If the amount of data available is greater +than the size of the buffer supplied, +the call supplies as much data as fits in the buffer provided +and returns with the error code +.Er ENOMEM . +If the old value is not desired, +.Fa oldp +and +.Fa oldlenp +should be set to NULL. +.Pp +The size of the available data can be determined by calling +.Fn sysctl +with the +.Dv NULL +argument for +.Fa oldp . +The size of the available data will be returned in the location pointed to by +.Fa oldlenp . +For some operations, the amount of space may change often. +For these operations, +the system attempts to round up so that the returned size is +large enough for a call to return the data shortly thereafter. +.Pp +To set a new value, +.Fa newp +is set to point to a buffer of length +.Fa newlen +from which the requested value is to be taken. +If a new value is not to be set, +.Fa newp +should be set to NULL and +.Fa newlen +set to 0. +.Pp +The +.Fn sysctlnametomib +function accepts an ASCII representation of the name, +looks up the integer name vector, +and returns the numeric representation in the mib array pointed to by +.Fa mibp . +The number of elements in the mib array is given by the location specified by +.Fa sizep +before the call, +and that location gives the number of entries copied after a successful call. +The resulting +.Fa mib +and +.Fa size +may be used in subsequent +.Fn sysctl +calls to get the data associated with the requested ASCII name. +This interface is intended for use by applications that want to +repeatedly request the same variable (the +.Fn sysctl +function runs in about a third the time as the same request made via the +.Fn sysctlbyname +function). +The +.Fn sysctlnametomib +function is also useful for fetching mib prefixes and then adding +a final component. +For example, to fetch process information +for processes with pid's less than 100: +.Pp +.Bd -literal -offset indent -compact +int i, mib[4]; +size_t len; +struct kinfo_proc kp; + +/* Fill out the first three components of the mib */ +len = 4; +sysctlnametomib("kern.proc.pid", mib, &len); + +/* Fetch and print entries for pid's < 100 */ +for (i = 0; i < 100; i++) { + mib[3] = i; + len = sizeof(kp); + if (sysctl(mib, 4, &kp, &len, NULL, 0) == -1) + perror("sysctl"); + else if (len > 0) + printkproc(&kp); +} +.Ed +.Pp +The top level names are defined with a CTL_ prefix in +.In sys/sysctl.h , +and are as follows. +The next and subsequent levels down are found in the include files +listed here, and described in separate sections below. +.Bl -column CTLXMACHDEPXXX "Next Level NamesXXXXXX" -offset indent +.It Sy Name Ta Sy Next Level Names Ta Sy Description +.It Dv CTL_DEBUG Ta In sys/sysctl.h Ta Debugging +.It Dv CTL_VFS Ta In sys/mount.h Ta File system +.It Dv CTL_HW Ta In sys/sysctl.h Ta Generic CPU, I/O +.It Dv CTL_KERN Ta In sys/sysctl.h Ta High kernel limits +.It Dv CTL_MACHDEP Ta In sys/sysctl.h Ta Machine dependent +.It Dv CTL_NET Ta In sys/socket.h Ta Networking +.It Dv CTL_USER Ta In sys/sysctl.h Ta User-level +.It Dv CTL_VM Ta In vm/vm_param.h Ta Virtual memory +.El +.Pp +For example, the following retrieves the maximum number of processes allowed +in the system: +.Pp +.Bd -literal -offset indent -compact +int mib[2], maxproc; +size_t len; + +mib[0] = CTL_KERN; +mib[1] = KERN_MAXPROC; +len = sizeof(maxproc); +sysctl(mib, 2, &maxproc, &len, NULL, 0); +.Ed +.Pp +To retrieve the standard search path for the system utilities: +.Pp +.Bd -literal -offset indent -compact +int mib[2]; +size_t len; +char *p; + +mib[0] = CTL_USER; +mib[1] = USER_CS_PATH; +sysctl(mib, 2, NULL, &len, NULL, 0); +p = malloc(len); +sysctl(mib, 2, p, &len, NULL, 0); +.Ed +.Ss CTL_DEBUG +The debugging variables vary from system to system. +A debugging variable may be added or deleted without need to recompile +.Fn sysctl +to know about it. +Each time it runs, +.Fn sysctl +gets the list of debugging variables from the kernel and +displays their current values. +The system defines twenty +.Pq Vt "struct ctldebug" +variables named +.Va debug0 +through +.Va debug19 . +They are declared as separate variables so that they can be +individually initialized at the location of their associated variable. +The loader prevents multiple use of the same variable by issuing errors +if a variable is initialized in more than one place. +For example, to export the variable +.Va dospecialcheck +as a debugging variable, the following declaration would be used: +.Pp +.Bd -literal -offset indent -compact +int dospecialcheck = 1; +struct ctldebug debug5 = { "dospecialcheck", &dospecialcheck }; +.Ed +.Ss CTL_VFS +A distinguished second level name, VFS_GENERIC, +is used to get general information about all file systems. +One of its third level identifiers is VFS_MAXTYPENUM +that gives the highest valid file system type number. +Its other third level identifier is VFS_CONF that +returns configuration information about the file system +type given as a fourth level identifier (see +.Xr getvfsbyname 3 +as an example of its use). +The remaining second level identifiers are the +file system type number returned by a +.Xr statfs 2 +call or from VFS_CONF. +The third level identifiers available for each file system +are given in the header file that defines the mount +argument structure for that file system. +.Ss CTL_HW +The string and integer information available for the CTL_HW level +is detailed below. +The changeable column shows whether a process with appropriate +privilege may change the value. +.Bl -column "Second Level Name" integerXXX Changeable -offset indent +.It Sy Second Level Name Ta Sy Type Ta Sy Changeable +.It Dv HW_MACHINE Ta string Ta no +.It Dv HW_MODEL Ta string Ta no +.It Dv HW_NCPU Ta integer Ta no +.It Dv HW_BYTEORDER Ta integer Ta no +.It Dv HW_PHYSMEM Ta integer Ta no +.It Dv HW_USERMEM Ta integer Ta no +.It Dv HW_PAGESIZE Ta integer Ta no +.\".It Dv HW_DISKNAMES Ta integer Ta no +.\".It Dv HW_DISKSTATS Ta integer Ta no +.It Dv HW_FLOATINGPT Ta integer Ta no +.It Dv HW_MACHINE_ARCH Ta string Ta no +.It Dv HW_REALMEM Ta integer Ta no +.It Dv HW_AVAILPAGES Ta integer Ta no +.El +.Bl -tag -width 6n +.It Li HW_MACHINE +The machine class. +.It Li HW_MODEL +The machine model +.It Li HW_NCPU +The number of cpus. +.It Li HW_BYTEORDER +The byteorder (4321 or 1234). +.It Li HW_PHYSMEM +Amount of physical memory (in bytes), minus the amount used by the kernel, +pre-loaded modules, and (on x86) the dcons buffer. +.It Li HW_USERMEM +Amount of memory (in bytes) which is not wired. +.It Li HW_PAGESIZE +The software page size. +.\".It Fa HW_DISKNAMES +.\".It Fa HW_DISKSTATS +.It Li HW_FLOATINGPT +Nonzero if the floating point support is in hardware. +.It Li HW_MACHINE_ARCH +The machine dependent architecture type. +.It Li HW_REALMEM +Amount of memory (in bytes) reported by the firmware. +That value is sometimes not sane; in that case, the kernel reports the max +memory address instead. +.It Li HW_AVAILPAGES +The same value as +.Li HW_PHYSMEM , +measured in pages rather than bytes. +.El +.Ss CTL_KERN +The string and integer information available for the CTL_KERN level +is detailed below. +The changeable column shows whether a process with appropriate +privilege may change the value. +The types of data currently available are process information, +system vnodes, the open file entries, routing table entries, +virtual memory statistics, load average history, and clock rate +information. +.Bl -column "KERNXMAXFILESPERPROCXXX" "struct clockrateXXX" -offset indent +.It Sy Second Level Name Ta Sy Type Ta Sy Changeable +.It Dv KERN_ARGMAX Ta integer Ta no +.It Dv KERN_ARND Ta integer Ta no +.It Dv KERN_BOOTFILE Ta string Ta yes +.It Dv KERN_BOOTTIME Ta struct timeval Ta no +.It Dv KERN_CLOCKRATE Ta struct clockinfo Ta no +.It Dv KERN_FILE Ta struct xfile Ta no +.It Dv KERN_HOSTID Ta integer Ta yes +.It Dv KERN_HOSTUUID Ta string Ta yes +.It Dv KERN_HOSTNAME Ta string Ta yes +.It Dv KERN_IOV_MAX Ta integer Ta yes +.It Dv KERN_JOB_CONTROL Ta integer Ta no +.It Dv KERN_LOCKF Ta struct kinfo_lockf Ta no +.It Dv KERN_LOGSIGEXIT Ta integer Ta yes +.It Dv KERN_MAXFILES Ta integer Ta yes +.It Dv KERN_MAXFILESPERPROC Ta integer Ta yes +.It Dv KERN_MAXPHYS Ta integer Ta no +.It Dv KERN_MAXPROC Ta integer Ta no +.It Dv KERN_MAXPROCPERUID Ta integer Ta yes +.It Dv KERN_MAXVNODES Ta integer Ta yes +.It Dv KERN_NGROUPS Ta integer Ta no +.It Dv KERN_NISDOMAINNAME Ta string Ta yes +.It Dv KERN_OSRELDATE Ta integer Ta no +.It Dv KERN_OSRELEASE Ta string Ta no +.It Dv KERN_OSREV Ta integer Ta no +.It Dv KERN_OSTYPE Ta string Ta no +.It Dv KERN_POSIX1 Ta integer Ta no +.It Dv KERN_PROC Ta node Ta not applicable +.It Dv KERN_PS_STRINGS Ta integer Ta no +.It Dv KERN_SAVED_IDS Ta integer Ta no +.It Dv KERN_SECURELVL Ta integer Ta raise only +.It Dv KERN_UPDATEINTERVAL Ta integer Ta no +.It Dv KERN_USRSTACK Ta integer Ta no +.It Dv KERN_VERSION Ta string Ta no +.El +.Bl -tag -width 6n +.It Li KERN_ARGMAX +The maximum bytes of argument to +.Xr execve 2 . +.It Li KERN_ARND +.Xr arc4rand 9 +Fills the buffer with random bytes from in-kernel random data generator. +This is an alternative interface for +.Xr read 2 +of +.Xr random 4 +device, which does not depend on accessibility and correct mounting options +of the +.Xr devfs 4 +node. +.It Li KERN_BOOTFILE +The full pathname of the file from which the kernel was loaded. +.It Li KERN_BOOTTIME +A +.Va struct timeval +structure is returned. +This structure contains the time that the system was booted. +.It Li KERN_CLOCKRATE +A +.Va struct clockinfo +structure is returned. +This structure contains the clock, statistics clock and profiling clock +frequencies, the number of micro-seconds per hz tick and the skew rate. +.It Li KERN_FILE +Return the entire file table. +The returned data consists of an array of +.Va struct xfile , +whose size depends on the current number of such objects in the system. +.It Li KERN_HOSTID +Get or set the host ID. +.It Li KERN_HOSTUUID +Get or set the host's universally unique identifier (UUID). +.It Li KERN_HOSTNAME +Get or set the hostname. +.It Li KERN_IOV_MAX +The maximum accepted number of elements in an input-output vector (iovec), +see +.Xr readv 2 +and +.Xr writev 2 . +.It Li KERN_JOB_CONTROL +Return 1 if job control is available on this system, otherwise 0. +.It Li KERN_LOCKF +Returns the list of the file advisory locks currently known to kernel. +.It Li KERN_LOGSIGEXIT +Controls logging of process exit due to untrapped signals. +.It Li KERN_MAXFILES +The maximum number of files that may be open in the system. +.It Li KERN_MAXFILESPERPROC +The maximum number of files that may be open for a single process. +This limit only applies to processes with an effective uid of nonzero +at the time of the open request. +Files that have already been opened are not affected if the limit +or the effective uid is changed. +.It Li KERN_MAXPHYS +Specifies the maximum block I/O size. +Can be changed by the tunable +.Ev kern.maxphys . +.It Li KERN_MAXPROC +The maximum number of concurrent processes the system will allow. +.It Li KERN_MAXPROCPERUID +The maximum number of concurrent processes the system will allow +for a single effective uid. +This limit only applies to processes with an effective uid of nonzero +at the time of a fork request. +Processes that have already been started are not affected if the limit +is changed. +.It Li KERN_MAXVNODES +The maximum number of vnodes available on the system. +.It Li KERN_NGROUPS +The maximum number of supplemental groups. +.It Li KERN_NISDOMAINNAME +The name of the current YP/NIS domain. +.It Li KERN_OSRELDATE +The kernel release version in the format +.Ar M Ns Ar mm Ns Ar R Ns Ar xx , +where +.Ar M +is the major version, +.Ar mm +is the two digit minor version, +.Ar R +is 0 if release branch, otherwise 1, +and +.Ar xx +is updated when the available APIs change. +.Pp +The userland release version is available from +.In osreldate.h ; +parse this file if you need to get the release version of +the currently installed userland. +.It Li KERN_OSRELEASE +The system release string. +.It Li KERN_OSREV +The system revision string. +.It Li KERN_OSTYPE +The system type string. +.It Li KERN_POSIX1 +The version of +.St -p1003.1 +with which the system +attempts to comply. +.It Li KERN_PROC +Return selected information about specific running processes. +.Pp +For the following names, an array of +.Va struct kinfo_proc +structures is returned, +whose size depends on the current number of such objects in the system. +.Bl -column "Third Level NameXXXXXX" "Fourth LevelXXXXXX" -offset indent +.It Sy Third Level Name Ta Sy Fourth Level +.It Dv KERN_PROC_ALL Ta None +.It Dv KERN_PROC_PID Ta A process ID +.It Dv KERN_PROC_PGRP Ta A process group +.It Dv KERN_PROC_SESSION Ta A session +.It Dv KERN_PROC_TTY Ta A tty device +.It Dv KERN_PROC_UID Ta An effective user ID +.It Dv KERN_PROC_RUID Ta A real user ID +.It Dv KERN_PROC_GID Ta An effective group ID +.It Dv KERN_PROC_RGID Ta A real group ID +.El +.Pp +For the following names, the miscellaneous information about the target +process, which is specified by the fourth level of the oid name, +is returned. +A process ID of +.Li \-1 +specifies the current process. +.Bl -column "Third Level NameXXXXXX" "TypeXXXXXX" -offset indent +.It Sy Third Level Name Ta Sy Fourth Level +.It Dv KERN_PROC_ARGS Ta "Set of strings" +.It Dv KERN_PROC_PATHNAME Ta "String" +.It Dv KERN_PROC_KSTACK Ta "struct kinfo_stack []" +.It Dv KERN_PROC_VMMAP Ta "struct kinfo_vmentry []" +.It Dv KERN_PROC_FILEDESC Ta "struct kinfo_file []" +.It Dv KERN_PROC_GROUPS Ta "gid_t []" +.It Dv KERN_PROC_ENV Ta "Set of strings" +.It Dv KERN_PROC_AUXV Ta "Elf_Auxinfo []" +.It Dv KERN_PROC_RLIMIT Ta "Integer" +.It Dv KERN_PROC_PS_STRINGS Ta "Integer" +.It Dv KERN_PROC_UMASK Ta "Integer/short" +.It Dv KERN_PROC_OSREL Ta "Integer" +.It Dv KERN_PROC_SIGTRAMP Ta "Integer" +.It Dv KERN_PROC_CWD Ta "String" +.It Dv KERN_PROC_NFDS Ta "Integer" +.It Dv KERN_PROC_SIGFASTBLK Ta "Integer" +.It Dv KERN_PROC_VM_LAYOUT Ta "struct kinfo_vm_layout" +.It Dv KERN_PROC_RLIMIT_USAGE Ta "rlim_t []" +.It Dv KERN_PROC_KQUEUE Ta "struct kinfo_knote []" +.El +.Pp +.Bl -tag -compact +.It Dv KERN_PROC_ARGS +The command line argument +array is returned in a flattened form, i.e., zero-terminated arguments +follow each other. +The total size of array is returned. +It is also possible for a process to set its own process title this way. +.It Dv KERN_PROC_PATHNAME +The path of the process' text file is returned. +.It Dv KERN_PROC_KSTACK +The in-kernel call stacks for the threads of the specified process. +.It Dv KERN_PROC_VMMAP +The description of the map entries for the process. +Also refer to +.Xr kinfo_getvmmap 3 . +.It Dv KERN_PROC_FILEDESC +The file descriptors for files opened in the specified process. +Also refer to +.Xr kinfo_getfile 3 . +.It Dv KERN_PROC_GROUPS +Groups associated with the process. +.It Dv KERN_PROC_ENV +The set of strings representing the environment of the specified process. +.Pp +Note that from the kernel point of view, environment exists only at the +time of +.Xr execve 2 +system call. +This node method tries to reconstruct the environment from the known +breadcrumbs left in the process address space, but it is not guaranteed +to succeed or to represent the current value as maintained by the program. +.It Dv KERN_PROC_AUXV +The set of ELF auxv entries. +See the note above about environment, which is also applicable to auxv. +.It Dv KERN_PROC_RLIMIT +Additinal OID name element must be supplied, specifiing the resource name +as in +.Xr getrlimit 2 . +The call returns the given resource limit for the process. +.It Dv KERN_PROC_PS_STRINGS +Returns the location of the +.Vt ps_strings +structure at the time of the last call to +.Xr execve 2 +in the specified process. +.It Dv KERN_PROC_UMASK +The current umask value, see +.Xr umask 2 . +.It Dv KERN_PROC_OSREL +The value of osrel for the process, that is the osrel the currently executed +image was compiled for. +Read from the note of the elf executable at +.Xr execve 2 +time. +Might be modified by the process. +.It Dv KERN_PROC_SIGTRAMP +Address of the signal trampoline in the process address space, +where, simplifying, the kernel passes control for signal delivery. +.It Dv KERN_PROC_CWD +Returns the current working directory for the process. +.It Dv KERN_PROC_NFDS +Returns the total number of opened file descriptors for the process. +.It Dv KERN_PROC_SIGFASTBLK +Returns the address of the +.Xr sigfastblock 2 +location, if active. +.It Dv KERN_PROC_VM_LAYOUT +Fills a structure describing process virtual address space layout. +.It Dv KERN_PROC_RLIMIT_USAGE +Like +.Dv KERN_PROC_RLIMIT , +but instead of the limit, returns the accounted resource usage. +For resources which do not have a meaningful current value, +.Li \-1 +is returned. +.It Dv KERN_PROC_KQUEUE +Fills an array of structures describing events registered with +the specified kqueue. +The next two node's values are the +.Va pid +and +.Va kqfd , +the process ID of the process, and the file descriptor of the kqueue +in that process, to query. +.El +.It Li KERN_PS_STRINGS +Reports the location of the process +.Vt ps_strings +structure after exec, for the ABI of the querying process. +.It Li KERN_SAVED_IDS +Returns 1 if saved set-group and saved set-user ID is available. +.It Li KERN_SECURELVL +The system security level. +This level may be raised by processes with appropriate privilege. +It may not be lowered. +.It Li KERN_USRSTACK +Reports the top of the main thread user stack for the current process. +.It Li KERN_VERSION +The system version string. +.El +.Ss CTL_NET +The string and integer information available for the CTL_NET level +is detailed below. +The changeable column shows whether a process with appropriate +privilege may change the value. +.Bl -column "Second Level NameXXXXXX" "routing messagesXXX" -offset indent +.It Sy Second Level Name Ta Sy Type Ta Sy Changeable +.It Dv PF_ROUTE Ta routing messages Ta no +.It Dv PF_INET Ta IPv4 values Ta yes +.It Dv PF_INET6 Ta IPv6 values Ta yes +.El +.Bl -tag -width 6n +.It Li PF_ROUTE +Return the entire routing table or a subset of it. +The data is returned as a sequence of routing messages (see +.Xr route 4 +for the header file, format and meaning). +The length of each message is contained in the message header. +.Pp +The third level name is a protocol number, which is currently always 0. +The fourth level name is an address family, which may be set to 0 to +select all address families. +The fifth, sixth, and seventh level names are as follows: +.Bl -column -offset indent "Fifth Level" "Sixth Level" "Seventh Level" +.It Sy Fifth level Ta Sy Sixth Level Ta Sy Seventh Level +.It Dv NET_RT_FLAGS Ta rtflags Ta None +.It Dv NET_RT_DUMP Ta None Ta None or fib number +.It Dv NET_RT_IFLIST Ta 0 or if_index Ta None +.It Dv NET_RT_IFMALIST Ta 0 or if_index Ta None +.It Dv NET_RT_IFLISTL Ta 0 or if_index Ta None +.It Dv NET_RT_NHOPS Ta None Ta fib number +.El +.Pp +The +.Dv NET_RT_IFMALIST +name returns information about multicast group memberships on all interfaces +if 0 is specified, or for the interface specified by +.Va if_index . +.Pp +The +.Dv NET_RT_IFLISTL +is like +.Dv NET_RT_IFLIST , +just returning message header structs with additional fields allowing the +interface to be extended without breaking binary compatibility. +The +.Dv NET_RT_IFLISTL +uses 'l' versions of the message header structures: +.Va struct if_msghdrl +and +.Va struct ifa_msghdrl . +.Pp +.Dv NET_RT_NHOPS +returns all nexthops for specified address family in given fib. +.It Li PF_INET +Get or set various global information about the IPv4 +(Internet Protocol version 4). +The third level name is the protocol. +The fourth level name is the variable name. +The currently defined protocols and names are: +.Bl -column ProtocolXX VariableXX TypeXX ChangeableXX +.It Sy Protocol Ta Sy Variable Ta Sy Type Ta Sy Changeable +.It icmp Ta bmcastecho Ta integer Ta yes +.It icmp Ta maskrepl Ta integer Ta yes +.It ip Ta forwarding Ta integer Ta yes +.It ip Ta redirect Ta integer Ta yes +.It ip Ta ttl Ta integer Ta yes +.It udp Ta checksum Ta integer Ta yes +.El +.Pp +The variables are as follows: +.Bl -tag -width 6n +.It Li icmp.bmcastecho +Returns 1 if an ICMP echo request to a broadcast or multicast address is +to be answered. +.It Li icmp.maskrepl +Returns 1 if ICMP network mask requests are to be answered. +.It Li ip.forwarding +Returns 1 when IP forwarding is enabled for the host, +meaning that the host is acting as a router. +.It Li ip.redirect +Returns 1 when ICMP redirects may be sent by the host. +This option is ignored unless the host is routing IP packets, +and should normally be enabled on all systems. +.It Li ip.ttl +The maximum time-to-live (hop count) value for an IP packet sourced by +the system. +This value applies to normal transport protocols, not to ICMP. +.It Li udp.checksum +Returns 1 when UDP checksums are being computed and checked. +Disabling UDP checksums is strongly discouraged. +.Pp +For variables net.inet.*.ipsec, please refer to +.Xr ipsec 4 . +.El +.It Li PF_INET6 +Get or set various global information about the IPv6 +(Internet Protocol version 6). +The third level name is the protocol. +The fourth level name is the variable name. +.Pp +For variables net.inet6.* please refer to +.Xr inet6 4 . +For variables net.inet6.*.ipsec6, please refer to +.Xr ipsec 4 . +.El +.Ss CTL_USER +The string and integer information available for the CTL_USER level +is detailed below. +The changeable column shows whether a process with appropriate +privilege may change the value. +.Bl -column "USER_COLL_WEIGHTS_MAXXXX" "integerXXX" -offset indent +.It Sy Second Level Name Ta Sy Type Ta Sy Changeable +.It Dv USER_BC_BASE_MAX Ta integer Ta no +.It Dv USER_BC_DIM_MAX Ta integer Ta no +.It Dv USER_BC_SCALE_MAX Ta integer Ta no +.It Dv USER_BC_STRING_MAX Ta integer Ta no +.It Dv USER_COLL_WEIGHTS_MAX Ta integer Ta no +.It Dv USER_CS_PATH Ta string Ta no +.It Dv USER_EXPR_NEST_MAX Ta integer Ta no +.It Dv USER_LINE_MAX Ta integer Ta no +.It Dv USER_LOCALBASE Ta string Ta no +.It Dv USER_POSIX2_CHAR_TERM Ta integer Ta no +.It Dv USER_POSIX2_C_BIND Ta integer Ta no +.It Dv USER_POSIX2_C_DEV Ta integer Ta no +.It Dv USER_POSIX2_FORT_DEV Ta integer Ta no +.It Dv USER_POSIX2_FORT_RUN Ta integer Ta no +.It Dv USER_POSIX2_LOCALEDEF Ta integer Ta no +.It Dv USER_POSIX2_SW_DEV Ta integer Ta no +.It Dv USER_POSIX2_UPE Ta integer Ta no +.It Dv USER_POSIX2_VERSION Ta integer Ta no +.It Dv USER_RE_DUP_MAX Ta integer Ta no +.It Dv USER_STREAM_MAX Ta integer Ta no +.It Dv USER_TZNAME_MAX Ta integer Ta no +.El +.Bl -tag -width 6n +.It Li USER_BC_BASE_MAX +The maximum ibase/obase values in the +.Xr bc 1 +utility. +.It Li USER_BC_DIM_MAX +The maximum array size in the +.Xr bc 1 +utility. +.It Li USER_BC_SCALE_MAX +The maximum scale value in the +.Xr bc 1 +utility. +.It Li USER_BC_STRING_MAX +The maximum string length in the +.Xr bc 1 +utility. +.It Li USER_COLL_WEIGHTS_MAX +The maximum number of weights that can be assigned to any entry of +the LC_COLLATE order keyword in the locale definition file. +.It Li USER_CS_PATH +Return a value for the +.Ev PATH +environment variable that finds all the standard utilities. +.It Li USER_EXPR_NEST_MAX +The maximum number of expressions that can be nested within +parenthesis by the +.Xr expr 1 +utility. +.It Li USER_LINE_MAX +The maximum length in bytes of a text-processing utility's input +line. +.It Li USER_LOCALBASE +Return the value of localbase that has been compiled into system utilities +that need to have access to resources provided by a port or package. +.It Li USER_POSIX2_CHAR_TERM +Return 1 if the system supports at least one terminal type capable of +all operations described in +.St -p1003.2 , +otherwise 0. +.It Li USER_POSIX2_C_BIND +Return 1 if the system's C-language development facilities support the +C-Language Bindings Option, otherwise 0. +.It Li USER_POSIX2_C_DEV +Return 1 if the system supports the C-Language Development Utilities Option, +otherwise 0. +.It Li USER_POSIX2_FORT_DEV +Return 1 if the system supports the FORTRAN Development Utilities Option, +otherwise 0. +.It Li USER_POSIX2_FORT_RUN +Return 1 if the system supports the FORTRAN Runtime Utilities Option, +otherwise 0. +.It Li USER_POSIX2_LOCALEDEF +Return 1 if the system supports the creation of locales, otherwise 0. +.It Li USER_POSIX2_SW_DEV +Return 1 if the system supports the Software Development Utilities Option, +otherwise 0. +.It Li USER_POSIX2_UPE +Return 1 if the system supports the User Portability Utilities Option, +otherwise 0. +.It Li USER_POSIX2_VERSION +The version of +.St -p1003.2 +with which the system attempts to comply. +.It Li USER_RE_DUP_MAX +The maximum number of repeated occurrences of a regular expression +permitted when using interval notation. +.It Li USER_STREAM_MAX +The minimum maximum number of streams that a process may have open +at any one time. +.It Li USER_TZNAME_MAX +The minimum maximum number of types supported for the name of a +timezone. +.El +.Ss CTL_VM +The string and integer information available for the CTL_VM level +is detailed below. +The changeable column shows whether a process with appropriate +privilege may change the value. +.Bl -column "Second Level NameXXXXXX" "struct loadavgXXX" -offset indent +.It Sy Second Level Name Ta Sy Type Ta Sy Changeable +.It Dv VM_LOADAVG Ta struct loadavg Ta no +.It Dv VM_TOTAL Ta struct vmtotal Ta no +.It Dv VM_SWAPPING_ENABLED Ta integer Ta maybe +.It Dv VM_V_FREE_MIN Ta integer Ta yes +.It Dv VM_V_FREE_RESERVED Ta integer Ta yes +.It Dv VM_V_FREE_TARGET Ta integer Ta yes +.It Dv VM_V_INACTIVE_TARGET Ta integer Ta yes +.It Dv VM_V_PAGEOUT_FREE_MIN Ta integer Ta yes +.It Dv VM_OVERCOMMIT Ta integer Ta yes +.El +.Bl -tag -width 6n +.It Li VM_LOADAVG +Return the load average history. +The returned data consists of a +.Va struct loadavg . +.It Li VM_TOTAL +Return the system wide virtual memory statistics. +The returned data consists of a +.Va struct vmtotal . +.It Li VM_SWAPPING_ENABLED +1 if process swapping is enabled or 0 if disabled. +This variable is +permanently set to 0 if the kernel was built with swapping disabled. +.It Li VM_V_FREE_MIN +Minimum amount of memory (cache memory plus free memory) +required to be available before a process waiting on memory will be +awakened. +.It Li VM_V_FREE_RESERVED +Processes will awaken the pageout daemon and wait for memory if the +number of free and cached pages drops below this value. +.It Li VM_V_FREE_TARGET +The total amount of free memory (including cache memory) that the +pageout daemon tries to maintain. +.It Li VM_V_INACTIVE_TARGET +The desired number of inactive pages that the pageout daemon should +achieve when it runs. +Inactive pages can be quickly inserted into +process address space when needed. +.It Li VM_V_PAGEOUT_FREE_MIN +If the amount of free and cache memory falls below this value, the +pageout daemon will enter "memory conserving mode" to avoid deadlock. +.It Li VM_OVERCOMMIT +Overcommit behaviour, as described in +.Xr tuning 7 . +.El +.Sh RETURN VALUES +.Rv -std +.Sh FILES +.Bl -tag -width <netinet/icmpXvar.h> -compact +.It In sys/sysctl.h +definitions for top level identifiers, second level kernel and hardware +identifiers, and user level identifiers +.It In sys/socket.h +definitions for second level network identifiers +.It In sys/gmon.h +definitions for third level profiling identifiers +.It In vm/vm_param.h +definitions for second level virtual memory identifiers +.It In netinet/in.h +definitions for third level IPv4/IPv6 identifiers and +fourth level IPv4/v6 identifiers +.It In netinet/icmp_var.h +definitions for fourth level ICMP identifiers +.It In netinet/icmp6.h +definitions for fourth level ICMPv6 identifiers +.It In netinet/udp_var.h +definitions for fourth level UDP identifiers +.El +.Sh ERRORS +The following errors may be reported: +.Bl -tag -width Er +.It Bq Er EFAULT +The buffer +.Fa name , +.Fa oldp , +.Fa newp , +or length pointer +.Fa oldlenp +contains an invalid address. +.It Bq Er EINVAL +The +.Fa name +array is less than two or greater than CTL_MAXNAME. +.It Bq Er EINVAL +A non-null +.Fa newp +is given and its specified length in +.Fa newlen +is too large or too small. +.It Bq Er ENOMEM +The length pointed to by +.Fa oldlenp +is too short to hold the requested value. +.It Bq Er ENOMEM +The smaller of either the length pointed to by +.Fa oldlenp +or the estimated size of the returned data exceeds the +system limit on locked memory. +.It Bq Er ENOMEM +Locking the buffer +.Fa oldp , +or a portion of the buffer if the estimated size of the data +to be returned is smaller, +would cause the process to exceed its per-process locked memory limit. +.It Bq Er ENOTDIR +The +.Fa name +array specifies an intermediate rather than terminal name. +.It Bq Er EISDIR +The +.Fa name +array specifies a terminal name, but the actual name is not terminal. +.It Bq Er ENOENT +The +.Fa name +array specifies a value that is unknown. +.It Bq Er EPERM +An attempt is made to set a read-only value. +.It Bq Er EPERM +A process without appropriate privilege attempts to set a value. +.El +.Sh SEE ALSO +.Xr confstr 3 , +.Xr kinfo_getproc 3 , +.Xr kvm 3 , +.Xr sysconf 3 , +.Xr sysctl 8 +.Sh HISTORY +The +.Fn sysctl +function first appeared in +.Bx 4.4 . diff --git a/lib/libc/gen/sysctl.c b/lib/libc/gen/sysctl.c new file mode 100644 index 000000000000..d6fadd3c3e5c --- /dev/null +++ b/lib/libc/gen/sysctl.c @@ -0,0 +1,213 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> + +#include <errno.h> +#include <limits.h> +#include <paths.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> + +extern int __sysctl(const int *name, u_int namelen, void *oldp, + size_t *oldlenp, const void *newp, size_t newlen); + +static int +set_user_str(void *dstp, size_t *dstlenp, const char *src, size_t len, + size_t maxlen) +{ + int retval; + + retval = 0; + if (dstp != NULL) { + if (len > maxlen) { + len = maxlen; + errno = ENOMEM; + retval = -1; + } + memcpy(dstp, src, len); + } + *dstlenp = len; + return (retval); +} + +int +sysctl(const int *name, u_int namelen, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen) +{ + int retval; + size_t orig_oldlen; + + orig_oldlen = oldlenp != NULL ? *oldlenp : 0; + retval = __sysctl(name, namelen, oldp, oldlenp, newp, newlen); + /* + * Valid names under CTL_USER except USER_LOCALBASE have a dummy entry + * in the sysctl tree (to support name lookups and enumerations) with + * an empty/zero value, and the true value is supplied by this routine. + * For all such names, __sysctl() is used solely to validate the name. + * + * Return here unless there was a successful lookup for a CTL_USER name. + */ + if (retval != 0 || name[0] != CTL_USER) + return (retval); + + if (namelen != 2) { + errno = EINVAL; + return (-1); + } + + /* Variables under CLT_USER that may be overridden by kernel values */ + switch (name[1]) { + case USER_LOCALBASE: + if (oldlenp == NULL || *oldlenp > sizeof("")) + return (0); + return (set_user_str(oldp, oldlenp, _PATH_LOCALBASE, + sizeof(_PATH_LOCALBASE), orig_oldlen)); + } + + /* Variables under CLT_USER whose values are immutably defined below */ + if (newp != NULL) { + errno = EPERM; + return (-1); + } + + switch (name[1]) { + case USER_CS_PATH: + return (set_user_str(oldp, oldlenp, _PATH_STDPATH, + sizeof(_PATH_STDPATH), orig_oldlen)); + } + + if (oldp != NULL && *oldlenp < sizeof(int)) { + errno = ENOMEM; + return (-1); + } + *oldlenp = sizeof(int); + if (oldp == NULL) + return (0); + + switch (name[1]) { + case USER_BC_BASE_MAX: + *(int *)oldp = BC_BASE_MAX; + return (0); + case USER_BC_DIM_MAX: + *(int *)oldp = BC_DIM_MAX; + return (0); + case USER_BC_SCALE_MAX: + *(int *)oldp = BC_SCALE_MAX; + return (0); + case USER_BC_STRING_MAX: + *(int *)oldp = BC_STRING_MAX; + return (0); + case USER_COLL_WEIGHTS_MAX: + *(int *)oldp = COLL_WEIGHTS_MAX; + return (0); + case USER_EXPR_NEST_MAX: + *(int *)oldp = EXPR_NEST_MAX; + return (0); + case USER_LINE_MAX: + *(int *)oldp = LINE_MAX; + return (0); + case USER_RE_DUP_MAX: + *(int *)oldp = RE_DUP_MAX; + return (0); + case USER_POSIX2_VERSION: + *(int *)oldp = _POSIX2_VERSION; + return (0); + case USER_POSIX2_C_BIND: +#ifdef POSIX2_C_BIND + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_POSIX2_C_DEV: +#ifdef POSIX2_C_DEV + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_POSIX2_CHAR_TERM: +#ifdef POSIX2_CHAR_TERM + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_POSIX2_FORT_DEV: +#ifdef POSIX2_FORT_DEV + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_POSIX2_FORT_RUN: +#ifdef POSIX2_FORT_RUN + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_POSIX2_LOCALEDEF: +#ifdef POSIX2_LOCALEDEF + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_POSIX2_SW_DEV: +#ifdef POSIX2_SW_DEV + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_POSIX2_UPE: +#ifdef POSIX2_UPE + *(int *)oldp = 1; +#else + *(int *)oldp = 0; +#endif + return (0); + case USER_STREAM_MAX: + *(int *)oldp = FOPEN_MAX; + return (0); + case USER_TZNAME_MAX: + *(int *)oldp = NAME_MAX; + return (0); + default: + errno = EINVAL; + return (-1); + } + /* NOTREACHED */ +} diff --git a/lib/libc/gen/sysctlbyname.c b/lib/libc/gen/sysctlbyname.c new file mode 100644 index 000000000000..8cc9599f7a95 --- /dev/null +++ b/lib/libc/gen/sysctlbyname.c @@ -0,0 +1,54 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2019 Pawel Biernacki, Mysterious Code Ltd. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/sysctl.h> +#include <string.h> + +extern int __sysctlbyname(const char *name, size_t namelen, void *oldp, + size_t *oldlenp, const void *newp, size_t newlen); + +int +sysctlbyname(const char *name, void *oldp, size_t *oldlenp, + const void *newp, size_t newlen) +{ + size_t len; + int oid[2]; + + if (__predict_true(strncmp(name, "user.", 5) != 0)) { + len = strlen(name); + return (__sysctlbyname(name, len, oldp, oldlenp, newp, + newlen)); + } else { + len = nitems(oid); + if (sysctlnametomib(name, oid, &len) == -1) + return (-1); + return (sysctl(oid, (u_int)len, oldp, oldlenp, newp, + newlen)); + } +} diff --git a/lib/libc/gen/sysctlnametomib.c b/lib/libc/gen/sysctlnametomib.c new file mode 100644 index 000000000000..e45d23e10714 --- /dev/null +++ b/lib/libc/gen/sysctlnametomib.c @@ -0,0 +1,54 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright 2001 The FreeBSD Project. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE FREEBSD PROJECT ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE FREEBSD PROJECT BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/sysctl.h> +#include <string.h> + +/* + * This function uses a presently undocumented interface to the kernel + * to walk the tree and get the type so it can print the value. + * This interface is under work and consideration, and should probably + * be killed with a big axe by the first person who can find the time. + * (be aware though, that the proper interface isn't as obvious as it + * may seem, there are various conflicting requirements. + */ +int +sysctlnametomib(const char *name, int *mibp, size_t *sizep) +{ + int oid[2]; + int error; + + oid[0] = CTL_SYSCTL; + oid[1] = CTL_SYSCTL_NAME2OID; + + *sizep *= sizeof(int); + error = sysctl(oid, 2, mibp, sizep, name, strlen(name)); + *sizep /= sizeof(int); + return (error); +} diff --git a/lib/libc/gen/syslog.3 b/lib/libc/gen/syslog.3 new file mode 100644 index 000000000000..62140554f4f5 --- /dev/null +++ b/lib/libc/gen/syslog.3 @@ -0,0 +1,301 @@ +.\" Copyright (c) 1985, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 3, 2023 +.Dt SYSLOG 3 +.Os +.Sh NAME +.Nm syslog , +.Nm vsyslog , +.Nm openlog , +.Nm closelog , +.Nm setlogmask +.Nd control system log +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In syslog.h +.Ft void +.Fn syslog "int priority" "const char *message" "..." +.Ft void +.Fn openlog "const char *ident" "int logopt" "int facility" +.Ft void +.Fn closelog void +.Ft int +.Fn setlogmask "int maskpri" +.In syslog.h +.In stdarg.h +.Ft void +.Fn vsyslog "int priority" "const char *message" "va_list args" +.Sh DESCRIPTION +The +.Fn syslog +function +writes +.Fa message +to the system message logger. +The message is then written to the system console, log files, +logged-in users, or forwarded to other machines as appropriate. +(See +.Xr syslogd 8 . ) +.Pp +The message is identical to a +.Xr printf 3 +format string, except that +.Ql %m +is replaced by the current error +message. +(As denoted by the global variable +.Va errno ; +see +.Xr strerror 3 . ) +A trailing newline is added if none is present. +.Pp +The +.Fn vsyslog +function +is an alternate form in which the arguments have already been captured +using the variable-length argument facilities of +.Xr stdarg 3 . +.Pp +The message is tagged with +.Fa priority . +Priorities are encoded as a +.Fa facility +and a +.Em level . +The facility describes the part of the system +generating the message. +The level is selected from the following +.Em ordered +(high to low) list: +.Bl -tag -width LOG_AUTHPRIV +.It Dv LOG_EMERG +A panic condition. +This is normally broadcast to all users. +.It Dv LOG_ALERT +A condition that should be corrected immediately, such as a corrupted +system database. +.It Dv LOG_CRIT +Critical conditions, e.g., hard device errors. +.It Dv LOG_ERR +Errors. +.It Dv LOG_WARNING +Warning messages. +.It Dv LOG_NOTICE +Conditions that are not error conditions, +but should possibly be handled specially. +.It Dv LOG_INFO +Informational messages. +.It Dv LOG_DEBUG +Messages that contain information +normally of use only when debugging a program. +.El +.Pp +The +.Fn openlog +function +provides for more specialized processing of the messages sent +by +.Fn syslog +and +.Fn vsyslog . +The +.Fa ident +argument +is a string that will be prepended to every message. +It may be formatted as +.Fa ident[N] +in which case decimal number +.Fa N +replaces the process id within messages. +The +.Fa logopt +argument +is a bit field specifying logging options, which is formed by +.Tn OR Ns 'ing +one or more of the following values: +.Bl -tag -width LOG_AUTHPRIV +.It Dv LOG_CONS +If +.Fn syslog +cannot pass the message to +.Xr syslogd 8 +it will attempt to write the message to the console +.Pq Dq Pa /dev/console . +.It Dv LOG_NDELAY +Open the connection to +.Xr syslogd 8 +immediately. +Normally the open is delayed until the first message is logged. +Useful for programs that need to manage the order in which file +descriptors are allocated. +.It Dv LOG_PERROR +Write the message to standard error output as well to the system log. +.It Dv LOG_PID +Log the process id with each message: useful for identifying +instantiations of daemons. +On +.Fx , +this option is enabled by default and cannot be disabled. +.El +.Pp +The +.Fa facility +argument encodes a default facility to be assigned to all messages +that do not have an explicit facility encoded: +.Bl -tag -width LOG_AUTHPRIV +.It Dv LOG_AUTH +The authorization system: +.Xr login 1 , +.Xr su 1 , +.Xr getty 8 , +etc. +.It Dv LOG_AUTHPRIV +The same as +.Dv LOG_AUTH , +but logged to a file readable only by +selected individuals. +.It Dv LOG_CONSOLE +Messages written to +.Pa /dev/console +by the kernel console output driver. +.It Dv LOG_CRON +The cron daemon: +.Xr cron 8 . +.It Dv LOG_DAEMON +System daemons, such as +.Xr routed 8 , +that are not provided for explicitly by other facilities. +.It Dv LOG_FTP +The file transfer protocol daemons: +.Xr ftpd 8 , +.Xr tftpd 8 . +.It Dv LOG_KERN +Messages generated by the kernel. +These cannot be generated by any user processes. +.It Dv LOG_LPR +The line printer spooling system: +.Xr lpr 1 , +.Xr lpc 8 , +.Xr lpd 8 , +etc. +.It Dv LOG_MAIL +The mail system. +.It Dv LOG_NEWS +The network news system. +.It Dv LOG_NTP +The network time protocol system. +.It Dv LOG_SECURITY +Security subsystems, such as +.Xr ipfw 4 . +.It Dv LOG_SYSLOG +Messages generated internally by +.Xr syslogd 8 . +.It Dv LOG_USER +Messages generated by random user processes. +This is the default facility identifier if none is specified. +.It Dv LOG_UUCP +The uucp system. +.It Dv LOG_LOCAL0 +Reserved for local use. +Similarly for +.Dv LOG_LOCAL1 +through +.Dv LOG_LOCAL7 . +.El +.Pp +The +.Fn closelog +function +can be used to close the log file. +.Pp +The +.Fn setlogmask +function +sets the log priority mask to +.Fa maskpri +and returns the previous mask. +Calls to +.Fn syslog +with a priority not set in +.Fa maskpri +are rejected. +The mask for an individual priority +.Fa pri +is calculated by the macro +.Fn LOG_MASK pri ; +the mask for all priorities up to and including +.Fa toppri +is given by the macro +.Fn LOG_UPTO toppri ; . +The default allows all priorities to be logged. +.Sh RETURN VALUES +The routines +.Fn closelog , +.Fn openlog , +.Fn syslog +and +.Fn vsyslog +return no value. +.Pp +The routine +.Fn setlogmask +always returns the previous log mask level. +.Sh EXAMPLES +.Bd -literal -offset indent -compact +syslog(LOG_ALERT, "who: internal error 23"); + +openlog("ftpd", LOG_PID | LOG_NDELAY, LOG_FTP); + +setlogmask(LOG_UPTO(LOG_ERR)); + +syslog(LOG_INFO, "Connection from host %d", CallingHost); + +syslog(LOG_ERR|LOG_LOCAL2, "foobar error: %m"); +.Ed +.Sh SEE ALSO +.Xr logger 1 , +.Xr syslogd 8 +.Sh HISTORY +These +functions appeared in +.Bx 4.2 . +.Sh BUGS +Never pass a string with user-supplied data as a format without using +.Ql %s . +An attacker can put format specifiers in the string to mangle your stack, +leading to a possible security hole. +This holds true even if the string was built using a function like +.Fn snprintf , +as the resulting string may still contain user-supplied conversion specifiers +for later interpolation by +.Fn syslog . +.Pp +Always use the proper secure idiom: +.Pp +.Dl syslog(priority, \*q%s\*q, string); diff --git a/lib/libc/gen/syslog.c b/lib/libc/gen/syslog.c new file mode 100644 index 000000000000..a6290ee81a29 --- /dev/null +++ b/lib/libc/gen/syslog.c @@ -0,0 +1,496 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/socket.h> +#include <sys/syslog.h> +#include <sys/time.h> +#include <sys/uio.h> +#include <sys/un.h> +#include <netdb.h> + +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <pthread.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <stdarg.h> +#include "un-namespace.h" + +#include "libc_private.h" + +/* Maximum number of characters of syslog message */ +#define MAXLINE 8192 + +static int LogFile = -1; /* fd for log */ +static bool connected; /* have done connect */ +static int opened; /* have done openlog() */ +static int LogStat = 0; /* status bits, set by openlog() */ +static pid_t LogPid = -1; /* process id to tag the entry with */ +static const char *LogTag = NULL; /* string to tag the entry with */ +static int LogTagLength = -1; /* usable part of LogTag */ +static int LogFacility = LOG_USER; /* default facility code */ +static int LogMask = 0xff; /* mask of priorities to be logged */ +static pthread_mutex_t syslog_mutex = PTHREAD_MUTEX_INITIALIZER; + +#define THREAD_LOCK() \ + do { \ + if (__isthreaded) _pthread_mutex_lock(&syslog_mutex); \ + } while(0) +#define THREAD_UNLOCK() \ + do { \ + if (__isthreaded) _pthread_mutex_unlock(&syslog_mutex); \ + } while(0) + +/* RFC5424 defined value. */ +#define NILVALUE "-" + +static void disconnectlog(void); /* disconnect from syslogd */ +static void connectlog(void); /* (re)connect to syslogd */ +static void openlog_unlocked(const char *, int, int); +static void parse_tag(void); /* parse ident[NNN] if needed */ + +/* + * Format of the magic cookie passed through the stdio hook + */ +struct bufcookie { + char *base; /* start of buffer */ + int left; +}; + +/* + * stdio write hook for writing to a static string buffer + * XXX: Maybe one day, dynamically allocate it so that the line length + * is `unlimited'. + */ +static int +writehook(void *cookie, const char *buf, int len) +{ + struct bufcookie *h; /* private `handle' */ + + h = (struct bufcookie *)cookie; + if (len > h->left) { + /* clip in case of wraparound */ + len = h->left; + } + if (len > 0) { + (void)memcpy(h->base, buf, len); /* `write' it. */ + h->base += len; + h->left -= len; + } + return len; +} + +/* + * syslog, vsyslog -- + * print message on log file; output is intended for syslogd(8). + */ +void +syslog(int pri, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsyslog(pri, fmt, ap); + va_end(ap); +} + +static void +vsyslog1(int pri, const char *fmt, va_list ap) +{ + struct timeval now; + struct tm tm; + char ch, *p; + long tz_offset; + int cnt, fd, saved_errno; + char hostname[MAXHOSTNAMELEN], *stdp, tbuf[MAXLINE], fmt_cpy[MAXLINE], + errstr[64], tz_sign; + FILE *fp, *fmt_fp; + struct bufcookie tbuf_cookie; + struct bufcookie fmt_cookie; + +#define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID + /* Check for invalid bits. */ + if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { + syslog(INTERNALLOG, + "syslog: unknown facility/priority: %x", pri); + pri &= LOG_PRIMASK|LOG_FACMASK; + } + + saved_errno = errno; + + /* Check priority against setlogmask values. */ + if (!(LOG_MASK(LOG_PRI(pri)) & LogMask)) + return; + + /* Set default facility if none specified. */ + if ((pri & LOG_FACMASK) == 0) + pri |= LogFacility; + + /* Create the primary stdio hook */ + tbuf_cookie.base = tbuf; + tbuf_cookie.left = sizeof(tbuf); + fp = fwopen(&tbuf_cookie, writehook); + if (fp == NULL) + return; + + /* Build the message according to RFC 5424. Tag and version. */ + (void)fprintf(fp, "<%d>1 ", pri); + /* Timestamp similar to RFC 3339. */ + if (gettimeofday(&now, NULL) == 0 && + localtime_r(&now.tv_sec, &tm) != NULL) { + if (tm.tm_gmtoff < 0) { + tz_sign = '-'; + tz_offset = -tm.tm_gmtoff; + } else { + tz_sign = '+'; + tz_offset = tm.tm_gmtoff; + } + + (void)fprintf(fp, + "%04d-%02d-%02d" /* Date. */ + "T%02d:%02d:%02d.%06ld" /* Time. */ + "%c%02ld:%02ld ", /* Time zone offset. */ + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, now.tv_usec, + tz_sign, tz_offset / 3600, (tz_offset % 3600) / 60); + } else + (void)fputs(NILVALUE " ", fp); + /* Hostname. */ + (void)gethostname(hostname, sizeof(hostname)); + (void)fprintf(fp, "%s ", + hostname[0] == '\0' ? NILVALUE : hostname); + if (LogStat & LOG_PERROR) { + /* Transfer to string buffer */ + (void)fflush(fp); + stdp = tbuf + (sizeof(tbuf) - tbuf_cookie.left); + } + /* Application name. */ + if (LogTag == NULL) + LogTag = _getprogname(); + else if (LogTagLength == -1) + parse_tag(); + if (LogTagLength > 0) + (void)fprintf(fp, "%.*s ", LogTagLength, LogTag); + else + (void)fprintf(fp, "%s ", LogTag == NULL ? NILVALUE : LogTag); + /* + * Provide the process ID regardless of whether LOG_PID has been + * specified, as it provides valuable information. Many + * applications tend not to use this, even though they should. + */ + if (LogTagLength <= 0) + LogPid = getpid(); + (void)fprintf(fp, "%d ", (int)LogPid); + /* Message ID. */ + (void)fputs(NILVALUE " ", fp); + /* Structured data. */ + (void)fputs(NILVALUE " ", fp); + + /* Check to see if we can skip expanding the %m */ + if (strstr(fmt, "%m")) { + + /* Create the second stdio hook */ + fmt_cookie.base = fmt_cpy; + fmt_cookie.left = sizeof(fmt_cpy) - 1; + fmt_fp = fwopen(&fmt_cookie, writehook); + if (fmt_fp == NULL) { + fclose(fp); + return; + } + + /* + * Substitute error message for %m. Be careful not to + * molest an escaped percent "%%m". We want to pass it + * on untouched as the format is later parsed by vfprintf. + */ + for ( ; (ch = *fmt); ++fmt) { + if (ch == '%' && fmt[1] == 'm') { + ++fmt; + strerror_r(saved_errno, errstr, sizeof(errstr)); + fputs(errstr, fmt_fp); + } else if (ch == '%' && fmt[1] == '%') { + ++fmt; + fputc(ch, fmt_fp); + fputc(ch, fmt_fp); + } else { + fputc(ch, fmt_fp); + } + } + + /* Null terminate if room */ + fputc(0, fmt_fp); + fclose(fmt_fp); + + /* Guarantee null termination */ + fmt_cpy[sizeof(fmt_cpy) - 1] = '\0'; + + fmt = fmt_cpy; + } + + /* Message. */ + (void)vfprintf(fp, fmt, ap); + (void)fclose(fp); + + cnt = sizeof(tbuf) - tbuf_cookie.left; + + /* Remove a trailing newline */ + if (tbuf[cnt - 1] == '\n') + cnt--; + + /* Output to stderr if requested. */ + if (LogStat & LOG_PERROR) { + struct iovec iov[2]; + struct iovec *v = iov; + + v->iov_base = stdp; + v->iov_len = cnt - (stdp - tbuf); + ++v; + v->iov_base = "\n"; + v->iov_len = 1; + (void)_writev(STDERR_FILENO, iov, 2); + } + + /* Get connected, output the message to the local logger. */ + if (!opened) + openlog_unlocked(LogTag, LogStat | LOG_NDELAY, 0); + connectlog(); + + /* + * If the send() failed, there are two likely scenarios: + * 1) syslogd was restarted. In this case make one (only) attempt + * to reconnect. + * 2) We filled our buffer due to syslogd not being able to read + * as fast as we write. In this case prefer to lose the current + * message rather than whole buffer of previously logged data. + */ + if (send(LogFile, tbuf, cnt, 0) < 0) { + if (errno != ENOBUFS) { + disconnectlog(); + connectlog(); + if (send(LogFile, tbuf, cnt, 0) >= 0) + return; + } + } else + return; + + /* + * Output the message to the console; try not to block + * as a blocking console should not stop other processes. + * Make sure the error reported is the one from the syslogd failure. + */ + if (LogStat & LOG_CONS && + (fd = _open(_PATH_CONSOLE, O_WRONLY|O_NONBLOCK|O_CLOEXEC, 0)) >= + 0) { + struct iovec iov[2]; + struct iovec *v = iov; + + p = strchr(tbuf, '>') + 3; + v->iov_base = p; + v->iov_len = cnt - (p - tbuf); + ++v; + v->iov_base = "\r\n"; + v->iov_len = 2; + (void)_writev(fd, iov, 2); + (void)_close(fd); + } +} + +static void +syslog_cancel_cleanup(void *arg __unused) +{ + + THREAD_UNLOCK(); +} + +void +vsyslog(int pri, const char *fmt, va_list ap) +{ + + THREAD_LOCK(); + pthread_cleanup_push(syslog_cancel_cleanup, NULL); + vsyslog1(pri, fmt, ap); + pthread_cleanup_pop(1); +} + +/* Should be called with mutex acquired */ +static void +disconnectlog(void) +{ + /* + * If the user closed the FD and opened another in the same slot, + * that's their problem. They should close it before calling on + * system services. + */ + if (LogFile != -1) { + _close(LogFile); + LogFile = -1; + } + connected = false; /* retry connect */ +} + +/* Should be called with mutex acquired */ +static void +connectlog(void) +{ + struct sockaddr_un SyslogAddr; /* AF_UNIX address of local logger */ + + if (LogFile == -1) { + socklen_t len; + + if ((LogFile = _socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, + 0)) == -1) + return; + if (_getsockopt(LogFile, SOL_SOCKET, SO_SNDBUF, &len, + &(socklen_t){sizeof(len)}) == 0) { + if (len < MAXLINE) { + len = MAXLINE; + (void)_setsockopt(LogFile, SOL_SOCKET, SO_SNDBUF, + &len, sizeof(len)); + } + } + } + if (!connected) { + SyslogAddr.sun_len = sizeof(SyslogAddr); + SyslogAddr.sun_family = AF_UNIX; + + (void)strncpy(SyslogAddr.sun_path, _PATH_LOG, + sizeof SyslogAddr.sun_path); + if (_connect(LogFile, (struct sockaddr *)&SyslogAddr, + sizeof(SyslogAddr)) != -1) + connected = true; + else { + (void)_close(LogFile); + LogFile = -1; + } + } +} + +static void +openlog_unlocked(const char *ident, int logstat, int logfac) +{ + if (ident != NULL) { + LogTag = ident; + LogTagLength = -1; + } + LogStat = logstat; + parse_tag(); + if (logfac != 0 && (logfac &~ LOG_FACMASK) == 0) + LogFacility = logfac; + + if (LogStat & LOG_NDELAY) /* open immediately */ + connectlog(); + + opened = 1; /* ident and facility has been set */ +} + +void +openlog(const char *ident, int logstat, int logfac) +{ + + THREAD_LOCK(); + pthread_cleanup_push(syslog_cancel_cleanup, NULL); + openlog_unlocked(ident, logstat, logfac); + pthread_cleanup_pop(1); +} + + +void +closelog(void) +{ + THREAD_LOCK(); + if (LogFile != -1) { + (void)_close(LogFile); + LogFile = -1; + } + LogTag = NULL; + LogTagLength = -1; + connected = false; + THREAD_UNLOCK(); +} + +/* setlogmask -- set the log mask level */ +int +setlogmask(int pmask) +{ + int omask; + + THREAD_LOCK(); + omask = LogMask; + if (pmask != 0) + LogMask = pmask; + THREAD_UNLOCK(); + return (omask); +} + +/* + * Obtain LogPid from LogTag formatted as per RFC 3164, + * Section 5.3 Originating Process Information: + * + * ident[NNN] + */ +static void +parse_tag(void) +{ + char *begin, *end, *p; + pid_t pid; + + if (LogTag == NULL || (LogStat & LOG_PID) != 0) + return; + /* + * LogTagLength is -1 if LogTag was not parsed yet. + * Avoid multiple passes over same LogTag. + */ + LogTagLength = 0; + + /* Check for presence of opening [ and non-empty ident. */ + if ((begin = strchr(LogTag, '[')) == NULL || begin == LogTag) + return; + /* Check for presence of closing ] at the very end and non-empty pid. */ + if ((end = strchr(begin + 1, ']')) == NULL || end[1] != 0 || + (end - begin) < 2) + return; + + /* Check for pid to contain digits only. */ + pid = (pid_t)strtol(begin + 1, &p, 10); + if (p != end) + return; + + LogPid = pid; + LogTagLength = begin - LogTag; +} diff --git a/lib/libc/gen/tcgetpgrp.3 b/lib/libc/gen/tcgetpgrp.3 new file mode 100644 index 000000000000..2c9bd2983e06 --- /dev/null +++ b/lib/libc/gen/tcgetpgrp.3 @@ -0,0 +1,74 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 28, 2022 +.Dt TCGETPGRP 3 +.Os +.Sh NAME +.Nm tcgetpgrp +.Nd get foreground process group ID +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft pid_t +.Fn tcgetpgrp "int fd" +.Sh DESCRIPTION +The +.Fn tcgetpgrp +function returns the value of the process group ID of the foreground +process group associated with the terminal device. +If there is no foreground process group, +.Fn tcgetpgrp +returns an invalid process ID. +.Sh ERRORS +If an error occurs, +.Fn tcgetpgrp +returns -1 and the global variable +.Va errno +is set to indicate the error, as follows: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid file descriptor. +.It Bq Er ENOTTY +The calling process does not have a controlling terminal or the +underlying terminal device represented by +.Fa fd +is not the controlling terminal. +.El +.Sh SEE ALSO +.Xr setpgid 2 , +.Xr setsid 2 , +.Xr tcsetpgrp 3 +.Sh STANDARDS +The +.Fn tcgetpgrp +function is expected to be compliant with the +.St -p1003.1-88 +specification. diff --git a/lib/libc/gen/tcgetsid.3 b/lib/libc/gen/tcgetsid.3 new file mode 100644 index 000000000000..d613f9d9d7cb --- /dev/null +++ b/lib/libc/gen/tcgetsid.3 @@ -0,0 +1,69 @@ +.\" Copyright (c) 2008 David Xu <davidxu@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 28, 2022 +.Dt TCGETSID 3 +.Os +.Sh NAME +.Nm tcgetsid +.Nd get session ID associated with a controlling terminal +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In termios.h +.Ft pid_t +.Fn tcgetsid "int fd" +.Sh DESCRIPTION +The +.Fn tcgetsid +function returns the process group ID of the session leader for a +controlling terminal specified by +.Fa fd . +.Sh ERRORS +If an error occurs, +.Fn tcgetsid +returns -1 and the global variable +.Va errno +is set to indicate the error, as follows: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid file descriptor. +.It Bq Er ENOTTY +The calling process does not have a controlling terminal or the +underlying terminal device represented by +.Fa fd +is not the controlling terminal. +.El +.Sh SEE ALSO +.Xr getsid 2 , +.Xr setsid 2 , +.Xr tcgetpgrp 3 , +.Xr tcsetsid 3 +.Sh STANDARDS +The +.Fn tcgetsid +function conforms to +.St -xpg4.2 . diff --git a/lib/libc/gen/tcgetwinsize.3 b/lib/libc/gen/tcgetwinsize.3 new file mode 100644 index 000000000000..cc3c288d8169 --- /dev/null +++ b/lib/libc/gen/tcgetwinsize.3 @@ -0,0 +1,162 @@ +.\"- +.\" Copyright (c) 2020 Soumendra Ganguly <soumendraganguly@gmail.com> +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY +.\" EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) BE +.\" LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +.\" BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +.\" WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +.\" OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +.\" EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" +.\" Portions of this text are reprinted and reproduced in electronic form +.\" from P1003.1-202x, Draft 1.1, Draft Standard for Information Technology -- +.\" Portable Operating System Interface (POSIX), The Open Group Base +.\" Specifications Issue 8, Copyright (C) 2020 by the Institute of +.\" Electrical and Electronics Engineers, Inc and The Open Group. In the +.\" event of any discrepancy between this version and the original IEEE and +.\" The Open Group Standard, the original IEEE and The Open Group Standard is +.\" the referee document. The original Standard can be obtained online at +.\" http://www.opengroup.org/unix/online.html. +.\" +.Dd December 28, 2020 +.Dt TCGETWINSIZE 3 +.Os +.Sh NAME +.Nm tcgetwinsize , +.Nm tcsetwinsize +.Nd get, set the size of a terminal window +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In termios.h +.Bd -literal +struct winsize { + unsigned short ws_row; /* number of rows, in characters */ + unsigned short ws_col; /* number of columns, in characters */ + unsigned short ws_xpixel; /* horizontal size, in pixels */ + unsigned short ws_ypixel; /* vertical size, in pixels */ +}; +.Ed +.Pp +.Ft int +.Fn tcgetwinsize "int fd" "struct winsize *w" +.Ft int +.Fn tcsetwinsize "int fd" "const struct winsize *w" +.Sh DESCRIPTION +The +.Fn tcgetwinsize +function gets the terminal window size of the terminal of which +.Fa fd +is an open file descriptor and stores it in the +.Vt winsize +structure of which +.Fa w +is a pointer. +.Pp +The +.Fn tcsetwinsize +function sets the terminal window size of the terminal of which +.Fa fd +is an open file descriptor from the +.Vt winsize +structure referenced by +.Fa w . +The change occurs immediately. +If the terminal window size of the terminal +is changed successfully to have a value that is different from the value that +it had before the +.Fn tcsetwinsize +call, then the +.Dv SIGWINCH +signal is sent to all those members of the foreground process group of the +terminal that have the terminal as their controlling terminal. +.Pp +The above declaration of +.Vt "struct winsize" +may not be literal. +It is provided only to list the accessible members. +Therefore, before calling +.Fn tcsetwinsize , +the members of the +.Vt winsize +structure must be initialized by calling +.Fn tcgetwinsize . +The information in a +.Vt winsize +structure is stored by the kernel in order to provide a consistent interface, +but it is not used by the kernel. +.Sh RETURN VALUE +.Rv -std tcgetwinsize tcsetwinsize +The terminal window size remains unchanged if +.Fn tcsetwinsize +fails. +.Pp +.Sh ERRORS +The following are the possible failure conditions: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument to +.Fn tcgetwinsize +or to +.Fn tcsetwinsize +is not a valid file descriptor. +.It Bq Er ENOTTY +The +.Fa fd +argument to +.Fn tcgetwinsize +or to +.Fn tcsetwinsize +is not associated with a character special device. +.It Bq Er EINVAL +The +.Fa w +argument to +.Fn tcsetwinsize +is not valid. +.It Bq Er EFAULT +The +.Fa w +argument to +.Fn tcgetwinsize +or to +.Fn tcsetwinsize +points outside the process's allocated address space. +.El +.Sh SEE ALSO +.Xr stty 1 , +.Xr ioctl 2 , +.Xr sigaction 2 , +.Xr termios 4 , +.Xr tty 4 +.Sh STANDARDS +The +.Fn tcgetwinsize +and +.Fn tcsetwinsize +functions are expected to conform to +.St -p1003.1 +Base Specifications, Issue 8. +The +.Fa ws_xpixel +and +.Fa ws_ypixel +members of +.Vt "struct winsize" +are FreeBSD extensions. diff --git a/lib/libc/gen/tcsendbreak.3 b/lib/libc/gen/tcsendbreak.3 new file mode 100644 index 000000000000..0eb132e22e8c --- /dev/null +++ b/lib/libc/gen/tcsendbreak.3 @@ -0,0 +1,176 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 11, 2017 +.Dt TCSENDBREAK 3 +.Os +.Sh NAME +.Nm tcsendbreak , +.Nm tcdrain , +.Nm tcflush , +.Nm tcflow +.Nd line control functions +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In termios.h +.Ft int +.Fn tcdrain "int fd" +.Ft int +.Fn tcflow "int fd" "int action" +.Ft int +.Fn tcflush "int fd" "int action" +.Ft int +.Fn tcsendbreak "int fd" "int len" +.Sh DESCRIPTION +The +.Fn tcdrain +function waits until all output written to the terminal referenced by +.Fa fd +has been transmitted to the terminal. +.Pp +The +.Fn tcflow +function suspends transmission of data to or the reception of data from +the terminal referenced by +.Fa fd +depending on the value of +.Fa action . +The value of +.Fa action +must be one of the following: +.Bl -tag -width "TCIOFF" +.It Fa TCOOFF +Suspend output. +.It Fa TCOON +Restart suspended output. +.It Fa TCIOFF +Transmit a STOP character, which is intended to cause the terminal to stop +transmitting data to the system. +(See the description of IXOFF in the +.Ql Input Modes +section of +.Xr termios 4 ) . +.It Fa TCION +Transmit a START character, which is intended to cause the terminal to start +transmitting data to the system. +(See the description of IXOFF in the +.Ql Input Modes +section of +.Xr termios 4 ) . +.El +.Pp +The +.Fn tcflush +function discards any data written to the terminal referenced by +.Fa fd +which has not been transmitted to the terminal, or any data received +from the terminal but not yet read, depending on the value of +.Fa action . +The value of +.Fa action +must be one of the following: +.Bl -tag -width "TCIOFLUSH" +.It Fa TCIFLUSH +Flush data received but not read. +.It Fa TCOFLUSH +Flush data written but not transmitted. +.It Fa TCIOFLUSH +Flush both data received but not read and data written but not transmitted. +.El +.Pp +The +.Fn tcsendbreak +function transmits a continuous stream of zero-valued bits for four-tenths +of a second to the terminal referenced by +.Fa fd . +The +.Fa len +argument is ignored in this implementation. +.Sh RETURN VALUES +Upon successful completion, all of these functions return a value of zero. +.Sh ERRORS +If any error occurs, a value of -1 is returned and the global variable +.Va errno +is set to indicate the error, as follows: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid file descriptor. +.It Bq Er EINVAL +The +.Fa action +argument is not a proper value. +.It Bq Er ENOTTY +The file associated with +.Fa fd +is not a terminal. +.It Bq Er EINTR +A signal interrupted the +.Fn tcdrain +function. +.It Bq Er EWOULDBLOCK +The configured timeout expired before the +.Fn tcdrain +function could write all buffered output. +.El +.Sh SEE ALSO +.Xr tcsetattr 3 , +.Xr termios 4 , +.Xr tty 4 , +.Xr comcontrol 8 +.Sh STANDARDS +The +.Fn tcsendbreak , +.Fn tcflush +and +.Fn tcflow +functions are expected to be compliant with the +.St -p1003.1-88 +specification. +.Pp +The +.Fn tcdrain +function is expected to be compliant with +.St -p1003.1-88 +when the drain wait value is set to zero with +.Xr comcontrol 8 , +or with +.Xr ioctl 2 +.Va TIOCSDRAINWAIT , +or with +.Xr sysctl 8 +.Va kern.tty_drainwait . +A non-zero drain wait value can result in +.Fn tcdrain +returning +.Va EWOULDBLOCK +without writing all output. +The default value for +.Va kern.tty_drainwait +is 300 seconds. diff --git a/lib/libc/gen/tcsetattr.3 b/lib/libc/gen/tcsetattr.3 new file mode 100644 index 000000000000..6afa90af556b --- /dev/null +++ b/lib/libc/gen/tcsetattr.3 @@ -0,0 +1,338 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 15, 2020 +.Dt TCSETATTR 3 +.Os +.Sh NAME +.Nm cfgetispeed , +.Nm cfsetispeed , +.Nm cfgetospeed , +.Nm cfsetospeed , +.Nm cfsetspeed , +.Nm cfmakeraw , +.Nm cfmakesane , +.Nm tcgetattr , +.Nm tcsetattr +.Nd manipulating the termios structure +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In termios.h +.Ft speed_t +.Fn cfgetispeed "const struct termios *t" +.Ft int +.Fn cfsetispeed "struct termios *t" "speed_t speed" +.Ft speed_t +.Fn cfgetospeed "const struct termios *t" +.Ft int +.Fn cfsetospeed "struct termios *t" "speed_t speed" +.Ft int +.Fn cfsetspeed "struct termios *t" "speed_t speed" +.Ft void +.Fn cfmakeraw "struct termios *t" +.Ft void +.Fn cfmakesane "struct termios *t" +.Ft int +.Fn tcgetattr "int fd" "struct termios *t" +.Ft int +.Fn tcsetattr "int fd" "int action" "const struct termios *t" +.Sh DESCRIPTION +The +.Fn cfmakeraw , +.Fn cfmakesane , +.Fn tcgetattr +and +.Fn tcsetattr +functions are provided for getting and setting the termios structure. +.Pp +The +.Fn cfgetispeed , +.Fn cfsetispeed , +.Fn cfgetospeed , +.Fn cfsetospeed +and +.Fn cfsetspeed +functions are provided for getting and setting the baud rate values in +the termios structure. +The effects of the functions on the terminal as described below +do not become effective, nor are all errors detected, until the +.Fn tcsetattr +function is called. +Certain values for baud rates set in the termios structure and passed to +.Fn tcsetattr +have special meanings. +These are discussed in the portion of the manual page that describes the +.Fn tcsetattr +function. +.Sh GETTING AND SETTING THE BAUD RATE +The input and output baud rates are found in the termios structure. +The unsigned integer +.Li speed_t +is typedef'd in the include file +.In termios.h . +The value of the integer corresponds directly to the baud rate being +represented, however, the following symbolic values are defined. +.Bd -literal +#define B0 0 +#define B50 50 +#define B75 75 +#define B110 110 +#define B134 134 +#define B150 150 +#define B200 200 +#define B300 300 +#define B600 600 +#define B1200 1200 +#define B1800 1800 +#define B2400 2400 +#define B4800 4800 +#define B9600 9600 +#define B19200 19200 +#define B38400 38400 +#ifndef _POSIX_SOURCE +#define EXTA 19200 +#define EXTB 38400 +#endif /*_POSIX_SOURCE */ +.Ed +.Pp +The +.Fn cfgetispeed +function returns the input baud rate in the termios structure referenced by +.Fa t . +.Pp +The +.Fn cfsetispeed +function sets the input baud rate in the termios structure referenced by +.Fa t +to +.Fa speed . +.Pp +The +.Fn cfgetospeed +function returns the output baud rate in the termios structure referenced by +.Fa t . +.Pp +The +.Fn cfsetospeed +function sets the output baud rate in the termios structure referenced by +.Fa t +to +.Fa speed . +.Pp +The +.Fn cfsetspeed +function sets both the input and output baud rate in the termios structure +referenced by +.Fa t +to +.Fa speed . +.Pp +Upon successful completion, the functions +.Fn cfsetispeed , +.Fn cfsetospeed , +and +.Fn cfsetspeed +return a value of 0. +Otherwise, a value of -1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh GETTING AND SETTING THE TERMIOS STATE +This section describes the functions that are used to control the general +terminal interface. +Unless otherwise noted for a specific command, these functions are restricted +from use by background processes. +Attempts to perform these operations shall cause the process group to be sent +a SIGTTOU signal. +If the calling process is blocking or ignoring SIGTTOU signals, the process +is allowed to perform the operation and the SIGTTOU signal is not sent. +.Pp +In all the functions, although +.Fa fd +is an open file descriptor, the functions affect the underlying terminal +file, not just the open file description associated with the particular +file descriptor. +.Pp +The +.Fn cfmakeraw +function sets the flags stored in the termios structure to a state disabling +all input and output processing, giving a +.Dq raw I/O path , +while the +.Fn cfmakesane +function sets them to a state similar to those of a newly created +terminal device. +It should be noted that there is no function to reverse this effect. +This is because there are a variety of processing options that could be +re-enabled and the correct method is for an application to snapshot the +current terminal state using the function +.Fn tcgetattr , +setting raw or sane mode with +.Fn cfmakeraw +or +.Fn cfmakesane +and the subsequent +.Fn tcsetattr , +and then using another +.Fn tcsetattr +with the saved state to revert to the previous terminal state. +.Pp +The +.Fn tcgetattr +function copies the parameters associated with the terminal referenced +by +.Fa fd +in the termios structure referenced by +.Fa t . +This function is allowed from a background process, however, the terminal +attributes may be subsequently changed by a foreground process. +.Pp +The +.Fn tcsetattr +function sets the parameters associated with the terminal from the +termios structure referenced by +.Fa t . +The +.Fa action +argument is one of +the following values, as specified in the include file +.In termios.h . +.Bl -tag -width "TCSADRAIN" +.It Fa TCSANOW +The change occurs immediately. +.It Fa TCSADRAIN +The change occurs after all output written to +.Fa fd +has been transmitted to the terminal. +This value of +.Fa action +should be used when changing parameters that affect output. +.It Fa TCSAFLUSH +The change occurs after all output written to +.Fa fd +has been transmitted to the terminal. +Additionally, any input that has been received but not read is discarded. +.El +.Pp +The +.Fa action +may be modified by +.Em or Ns 'ing +in +.Fa TCSASOFT +which causes the values of the +.Va c_cflag , +.Va c_ispeed , +and +.Va c_ospeed +fields to be ignored. +.Pp +The 0 baud rate is used to terminate the connection. +If 0 is specified as the output speed to the function +.Fn tcsetattr , +modem control will no longer be asserted on the terminal, disconnecting +the terminal. +.Pp +If zero is specified as the input speed to the function +.Fn tcsetattr , +the input baud rate will be set to the same value as that specified by +the output baud rate. +.Pp +If +.Fn tcsetattr +is unable to make any of the requested changes, it returns -1 and +sets errno. +Otherwise, it makes all of the requested changes it can. +If the specified input and output baud rates differ and are a combination +that is not supported, neither baud rate is changed. +.Pp +Upon successful completion, the functions +.Fn tcgetattr +and +.Fn tcsetattr +return a value of 0. +Otherwise, they +return -1 and the global variable +.Va errno +is set to indicate the error, as follows: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument to +.Fn tcgetattr +or +.Fn tcsetattr +was not a valid file descriptor. +.It Bq Er EINTR +The +.Fn tcsetattr +function was interrupted by a signal. +.It Bq Er EINVAL +The +.Fa action +argument to the +.Fn tcsetattr +function was not valid, or an attempt was made to change an attribute +represented in the termios structure to an unsupported value. +.It Bq Er ENOTTY +The file associated with the +.Fa fd +argument to +.Fn tcgetattr +or +.Fn tcsetattr +is not a terminal. +.El +.Sh SEE ALSO +.Xr tcsendbreak 3 , +.Xr termios 4 +.Sh STANDARDS +The +.Fn cfgetispeed , +.Fn cfsetispeed , +.Fn cfgetospeed , +.Fn cfsetospeed , +.Fn tcgetattr +and +.Fn tcsetattr +functions are expected to be compliant with the +.St -p1003.1-88 +specification. +The +.Fn cfmakeraw , +.Fn cfmakesane +and +.Fn cfsetspeed +functions, +as well as the +.Li TCSASOFT +option to the +.Fn tcsetattr +function are extensions to the +.St -p1003.1-88 +specification. diff --git a/lib/libc/gen/tcsetpgrp.3 b/lib/libc/gen/tcsetpgrp.3 new file mode 100644 index 000000000000..4ae67d4520bf --- /dev/null +++ b/lib/libc/gen/tcsetpgrp.3 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 28, 2022 +.Dt TCSETPGRP 3 +.Os +.Sh NAME +.Nm tcsetpgrp +.Nd set foreground process group ID +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft int +.Fn tcsetpgrp "int fd" "pid_t pgrp_id" +.Sh DESCRIPTION +If the process has a controlling terminal, the +.Fn tcsetpgrp +function sets the foreground process group ID associated with the +terminal device to +.Fa pgrp_id . +The terminal device associated with +.Fa fd +must be the controlling terminal of the calling process and the +controlling terminal must be currently associated with the session +of the calling process. +The value of +.Fa pgrp_id +must be the same as the process group ID of a process in the same +session as the calling process. +.Sh RETURN VALUES +.Rv -std tcsetpgrp +.Sh ERRORS +The +.Fn tcsetpgrp +function will fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid file descriptor. +.It Bq Er EINVAL +An invalid value of +.Fa pgrp_id +was specified. +.It Bq Er ENOTTY +The calling process does not have a controlling terminal, or the file +represented by +.Fa fd +is not the controlling terminal, or the controlling terminal is no +longer associated with the session of the calling process. +.It Bq Er EPERM +The +.Fa pgrp_id +argument does not match the process group ID of a process in the same +session as the calling process. +.El +.Sh SEE ALSO +.Xr setpgid 2 , +.Xr setsid 2 , +.Xr tcgetpgrp 3 +.Sh STANDARDS +The +.Fn tcsetpgrp +function is expected to be compliant with the +.St -p1003.1-88 +specification. diff --git a/lib/libc/gen/tcsetsid.3 b/lib/libc/gen/tcsetsid.3 new file mode 100644 index 000000000000..a0a1907a6434 --- /dev/null +++ b/lib/libc/gen/tcsetsid.3 @@ -0,0 +1,89 @@ +.\" Copyright (c) 2009 Ed Schouten <ed@FreeBSD.org> +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd November 28, 2022 +.Dt TCSETSID 3 +.Os +.Sh NAME +.Nm tcsetsid +.Nd set session ID associated with a controlling terminal +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In termios.h +.Ft int +.Fn tcsetsid "int fd" "pid_t pid" +.Sh DESCRIPTION +The +.Fn tcsetsid +function sets associates a session identified by +.Fa pid +with a controlling terminal specified by +.Fa fd . +.Pp +This implementation only allows the controlling terminal to be changed +by the session leader itself. +This implies that +.Fa pid +always has to be equal to the process ID. +.Pp +It is unsupported to associate with a terminal that already has an +associated session. +Conversely, it is also unsupported to associate to a terminal when +the session is already associated with a different terminal. +.Sh ERRORS +If an error occurs, +.Fn tcsetsid +returns -1 and the global variable +.Va errno +is set to indicate the error, as follows: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument is not a valid file descriptor. +.It Bq Er ENOTTY +The file descriptor represented by +.Fa fd +is not a terminal. +.It Bq Er EINVAL +The +.Fa pid +argument is not equal to the session ID of the calling process. +.It Bq Er EPERM +The calling process is not a session leader. +.It Bq Er EPERM +The session already has an associated terminal or the terminal already +has an associated session. +.El +.Sh SEE ALSO +.Xr getsid 2 , +.Xr setsid 2 , +.Xr tcgetpgrp 3 , +.Xr tcgetsid 3 +.Sh HISTORY +A +.Fn tcsetsid +function first appeared in QNX. +It does not comply to any standard. diff --git a/lib/libc/gen/telldir.c b/lib/libc/gen/telldir.c new file mode 100644 index 000000000000..1731cc4d7a2c --- /dev/null +++ b/lib/libc/gen/telldir.c @@ -0,0 +1,204 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/param.h> +#include <sys/queue.h> +#include <dirent.h> +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" +#include "gen-private.h" +#include "telldir.h" + +/* + * return a pointer into a directory + */ +long +telldir(DIR *dirp) +{ + struct ddloc_mem *lp, *flp; + union ddloc_packed ddloc; + + if (__isthreaded) + _pthread_mutex_lock(&dirp->dd_lock); + /* + * Outline: + * 1) If the directory position fits in a packed structure, return that. + * 2) Otherwise, see if it's already been recorded in the linked list + * 3) Otherwise, malloc a new one + */ + if (dirp->dd_seek < (off_t)(1l << DD_SEEK_BITS) && + dirp->dd_loc < (1l << DD_LOC_BITS)) { + ddloc.s.is_packed = 1; + ddloc.s.loc = dirp->dd_loc; + ddloc.s.seek = dirp->dd_seek; + goto out; + } + + flp = NULL; + LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) { + if (lp->loc_seek == dirp->dd_seek) { + if (flp == NULL) + flp = lp; + if (lp->loc_loc == dirp->dd_loc) + break; + } else if (flp != NULL) { + lp = NULL; + break; + } + } + if (lp == NULL) { + lp = malloc(sizeof(struct ddloc_mem)); + if (lp == NULL) { + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); + return (-1); + } + lp->loc_index = dirp->dd_td->td_loccnt++; + lp->loc_seek = dirp->dd_seek; + lp->loc_loc = dirp->dd_loc; + if (flp != NULL) + LIST_INSERT_BEFORE(flp, lp, loc_lqe); + else + LIST_INSERT_HEAD(&dirp->dd_td->td_locq, lp, loc_lqe); + } + ddloc.i.is_packed = 0; + /* + * Technically this assignment could overflow on 32-bit architectures, + * but we would get ENOMEM long before that happens. + */ + ddloc.i.index = lp->loc_index; + +out: + if (__isthreaded) + _pthread_mutex_unlock(&dirp->dd_lock); + return (ddloc.l); +} + +/* + * seek to an entry in a directory. + * Only values returned by "telldir" should be passed to seekdir. + */ +void +_seekdir(DIR *dirp, long loc) +{ + struct ddloc_mem *lp; + struct dirent *dp; + union ddloc_packed ddloc; + off_t loc_seek; + size_t loc_loc; + + ddloc.l = loc; + + if (ddloc.s.is_packed) { + loc_seek = ddloc.s.seek; + loc_loc = ddloc.s.loc; + } else { + LIST_FOREACH(lp, &dirp->dd_td->td_locq, loc_lqe) { + if (lp->loc_index == ddloc.i.index) + break; + } + if (lp == NULL) + return; + + loc_seek = lp->loc_seek; + loc_loc = lp->loc_loc; + } + if (loc_loc == dirp->dd_loc && loc_seek == dirp->dd_seek) + return; + + /* If it's within the same chunk of data, don't bother reloading. */ + if (loc_seek == dirp->dd_seek) { + /* + * If we go back to 0 don't make the next readdir + * trigger a call to getdirentries(). + */ + if (loc_loc == 0) + dirp->dd_flags |= __DTF_SKIPREAD; + dirp->dd_loc = loc_loc; + return; + } + (void) lseek(dirp->dd_fd, (off_t)loc_seek, SEEK_SET); + dirp->dd_seek = loc_seek; + dirp->dd_loc = 0; + dirp->dd_flags &= ~__DTF_SKIPREAD; /* current contents are invalid */ + while (dirp->dd_loc < loc_loc) { + dp = _readdir_unlocked(dirp, 0); + if (dp == NULL) + break; + } +} + +/* + * After readdir returns the last entry in a block, a call to telldir + * returns a location that is after the end of that last entry. + * However, that location doesn't refer to a valid directory entry. + * Ideally, the call to telldir would return a location that refers to + * the first entry in the next block. That location is not known + * until the next block is read, so readdir calls this function after + * fetching a new block to fix any such telldir locations. + */ +void +_fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc) +{ + struct ddloc_mem *lp; + + lp = LIST_FIRST(&dirp->dd_td->td_locq); + if (lp != NULL) { + if (lp->loc_loc == oldloc && + lp->loc_seek == oldseek) { + lp->loc_seek = dirp->dd_seek; + lp->loc_loc = dirp->dd_loc; + } + } +} + +/* + * Reclaim memory for telldir cookies which weren't used. + */ +void +_reclaim_telldir(DIR *dirp) +{ + struct ddloc_mem *lp; + struct ddloc_mem *templp; + + lp = LIST_FIRST(&dirp->dd_td->td_locq); + while (lp != NULL) { + templp = lp; + lp = LIST_NEXT(lp, loc_lqe); + free(templp); + } + LIST_INIT(&dirp->dd_td->td_locq); +} diff --git a/lib/libc/gen/telldir.h b/lib/libc/gen/telldir.h new file mode 100644 index 000000000000..02fd52af9060 --- /dev/null +++ b/lib/libc/gen/telldir.h @@ -0,0 +1,111 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Copyright (c) 2000 + * Daniel Eischen. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _TELLDIR_H_ +#define _TELLDIR_H_ + +#include <sys/queue.h> +#include <stdbool.h> + +/* + * telldir will malloc one of these to describe the current directory position, + * if it can't fit that information into the packed structure below. It + * records the current magic cookie returned by getdirentries and the offset + * within the buffer associated with that return value. + */ +struct ddloc_mem { + LIST_ENTRY(ddloc_mem) loc_lqe; /* entry in list */ + size_t loc_index; /* key associated with structure */ + off_t loc_seek; /* magic cookie returned by getdirentries */ + size_t loc_loc; /* offset of entry in buffer */ +}; + +#ifdef __LP64__ +#define DD_LOC_BITS 31 +#define DD_SEEK_BITS 32 +#define DD_INDEX_BITS 63 +#else +#define DD_LOC_BITS 12 +#define DD_SEEK_BITS 19 +#define DD_INDEX_BITS 31 +#endif + +/* + * This is the real type returned by telldir. telldir will prefer to return + * the packed type, if possible, or the malloced type otherwise. For msdosfs, + * UFS, and NFS, directory positions usually fit within the packed type. For + * ZFS and tmpfs, they usually fit within the packed type on 64-bit + * architectures. + */ +union ddloc_packed { + long l; /* Opaque type returned by telldir(3) */ + struct { + /* Identifies union type. Must be 0. */ + unsigned long is_packed:1; + /* Index into directory's linked list of ddloc_mem */ + unsigned long index:DD_INDEX_BITS; + } __packed i; + struct { + /* Identifies union type. Must be 1. */ + unsigned long is_packed:1; + /* offset of entry in buffer*/ + unsigned long loc:DD_LOC_BITS; + /* magic cookie returned by getdirentries */ + unsigned long seek:DD_SEEK_BITS; + } __packed s; +}; + +_Static_assert(sizeof(long) == sizeof(union ddloc_packed), + "packed telldir size mismatch!"); + +/* + * One of these structures is malloced for each DIR to record telldir + * positions. + */ +struct _telldir { + LIST_HEAD(, ddloc_mem) td_locq; /* list of locations */ + long td_loccnt; /* index of entry for sequential readdir's */ +}; + +bool _filldir(DIR *, bool); +struct dirent *_readdir_unlocked(DIR *, int); +void _reclaim_telldir(DIR *); +void _seekdir(DIR *, long); +void _fixtelldir(DIR *dirp, off_t oldseek, size_t oldloc); +DIR *__opendir_common(int, int, bool); + +#define RDU_SKIP 0x0001 +#define RDU_SHORT 0x0002 + +#endif diff --git a/lib/libc/gen/termios.c b/lib/libc/gen/termios.c new file mode 100644 index 000000000000..2178cc7c419d --- /dev/null +++ b/lib/libc/gen/termios.c @@ -0,0 +1,287 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/ioctl.h> +#include <sys/time.h> + +#include <errno.h> +#include <string.h> +#define TTYDEFCHARS +#include <termios.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" + +int +tcgetattr(int fd, struct termios *t) +{ + + return (_ioctl(fd, TIOCGETA, t)); +} + +int +tcsetattr(int fd, int opt, const struct termios *t) +{ + struct termios localterm; + + if (opt & TCSASOFT) { + localterm = *t; + localterm.c_cflag |= CIGNORE; + t = &localterm; + } + switch (opt & ~TCSASOFT) { + case TCSANOW: + return (_ioctl(fd, TIOCSETA, t)); + case TCSADRAIN: + return (_ioctl(fd, TIOCSETAW, t)); + case TCSAFLUSH: + return (_ioctl(fd, TIOCSETAF, t)); + default: + errno = EINVAL; + return (-1); + } +} + +int +tcsetpgrp(int fd, pid_t pgrp) +{ + int s; + + s = pgrp; + return (_ioctl(fd, TIOCSPGRP, &s)); +} + +pid_t +tcgetpgrp(int fd) +{ + int s; + + if (_ioctl(fd, TIOCGPGRP, &s) < 0) + return ((pid_t)-1); + + return ((pid_t)s); +} + +pid_t +tcgetsid(int fd) +{ + int s; + + if (_ioctl(fd, TIOCGSID, &s) < 0) + return ((pid_t)-1); + + return ((pid_t)s); +} + +int +tcsetsid(int fd, pid_t pid) +{ + + if (pid != getsid(0)) { + errno = EINVAL; + return (-1); + } + + return (_ioctl(fd, TIOCSCTTY, NULL)); +} + +speed_t +cfgetospeed(const struct termios *t) +{ + + return (t->c_ospeed); +} + +speed_t +cfgetispeed(const struct termios *t) +{ + + return (t->c_ispeed); +} + +int +cfsetospeed(struct termios *t, speed_t speed) +{ + + t->c_ospeed = speed; + return (0); +} + +int +cfsetispeed(struct termios *t, speed_t speed) +{ + + t->c_ispeed = speed; + return (0); +} + +int +cfsetspeed(struct termios *t, speed_t speed) +{ + + t->c_ispeed = t->c_ospeed = speed; + return (0); +} + +/* + * Make a pre-existing termios structure into "raw" mode: character-at-a-time + * mode with no characters interpreted, 8-bit data path. + */ +void +cfmakeraw(struct termios *t) +{ + + t->c_iflag &= ~(IMAXBEL|IXOFF|INPCK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON|IGNPAR); + t->c_iflag |= IGNBRK; + t->c_oflag &= ~OPOST; + t->c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|ICANON|ISIG|IEXTEN|NOFLSH|TOSTOP|PENDIN); + t->c_cflag &= ~(CSIZE|PARENB); + t->c_cflag |= CS8|CREAD; + t->c_cc[VMIN] = 1; + t->c_cc[VTIME] = 0; +} + +/* + * Obtain a termios structure which is similar to the one provided by + * the kernel. + */ +void +cfmakesane(struct termios *t) +{ + + t->c_cflag = TTYDEF_CFLAG; + t->c_iflag = TTYDEF_IFLAG; + t->c_lflag = TTYDEF_LFLAG; + t->c_oflag = TTYDEF_OFLAG; + t->c_ispeed = TTYDEF_SPEED; + t->c_ospeed = TTYDEF_SPEED; + memcpy(&t->c_cc, ttydefchars, sizeof ttydefchars); +} + +int +tcsendbreak(int fd, int len __unused) +{ + struct timeval sleepytime; + + sleepytime.tv_sec = 0; + sleepytime.tv_usec = 400000; + if (_ioctl(fd, TIOCSBRK, 0) == -1) + return (-1); + (void)_select(0, 0, 0, 0, &sleepytime); + if (_ioctl(fd, TIOCCBRK, 0) == -1) + return (-1); + return (0); +} + +int +__libc_tcdrain(int fd) +{ + + return (_ioctl(fd, TIOCDRAIN, 0)); +} + +#pragma weak tcdrain +int +tcdrain(int fd) +{ + + return (((int (*)(int)) + __libc_interposing[INTERPOS_tcdrain])(fd)); +} + +__weak_reference(__libc_tcdrain, __tcdrain); +__weak_reference(__libc_tcdrain, _tcdrain); + +int +tcflush(int fd, int which) +{ + int com; + + switch (which) { + case TCIFLUSH: + com = FREAD; + break; + case TCOFLUSH: + com = FWRITE; + break; + case TCIOFLUSH: + com = FREAD | FWRITE; + break; + default: + errno = EINVAL; + return (-1); + } + return (_ioctl(fd, TIOCFLUSH, &com)); +} + +int +tcflow(int fd, int action) +{ + struct termios term; + u_char c; + + switch (action) { + case TCOOFF: + return (_ioctl(fd, TIOCSTOP, 0)); + case TCOON: + return (_ioctl(fd, TIOCSTART, 0)); + case TCION: + case TCIOFF: + if (tcgetattr(fd, &term) == -1) + return (-1); + c = term.c_cc[action == TCIOFF ? VSTOP : VSTART]; + if (c != _POSIX_VDISABLE && _write(fd, &c, sizeof(c)) == -1) + return (-1); + return (0); + default: + errno = EINVAL; + return (-1); + } + /* NOTREACHED */ +} + +int +tcgetwinsize(int fd, struct winsize *w) +{ + + return (_ioctl(fd, TIOCGWINSZ, w)); +} + +int +tcsetwinsize(int fd, const struct winsize *w) +{ + + return (_ioctl(fd, TIOCSWINSZ, w)); +} diff --git a/lib/libc/gen/time.3 b/lib/libc/gen/time.3 new file mode 100644 index 000000000000..6df74df2dcb4 --- /dev/null +++ b/lib/libc/gen/time.3 @@ -0,0 +1,139 @@ +.\" Copyright (c) 1989, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" This code is derived from software contributed to Berkeley by +.\" the American National Standards Committee X3, on Information +.\" Processing Systems. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 14, 2022 +.Dt TIME 3 +.Os +.Sh NAME +.Nm time +.Nd get time of day +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In time.h +.Ft time_t +.Fn time "time_t *tloc" +.Sh DESCRIPTION +The +.Fn time +function +returns the value of time in seconds since 0 hours, 0 minutes, +0 seconds, January 1, 1970, Coordinated Universal Time (UTC). +If an error occurs, +.Fn time +returns the value +.Po Vt time_t Pc Ns \-1 . +.Pp +The return value is also stored in +.No \&* Ns Va tloc , +provided that +.Va tloc +is non-null. +.Sh ERRORS +The +.Fn time +function may fail for any of the reasons described in +.Xr clock_gettime 2 . +.Sh SEE ALSO +.Xr clock_gettime 2 , +.Xr gettimeofday 2 , +.Xr ctime 3 +.Sh STANDARDS +The +.Nm +function conforms to +.St -p1003.1-2008 . +.Sh HISTORY +The +.Fn time +system call first appeared in +.At v1 . +Through the +.At v3 , +it returned 60 Hz ticks since an epoch that changed occasionally, because it +was a 32-bit value that overflowed in a little over 2 years. +.Pp +In +.At v4 +the granularity of the return value was reduced to whole seconds, +delaying the aforementioned overflow until 2038. +.Pp +.At v7 +introduced the +.Fn ftime +system call, which returned time at a millisecond level, +though retained the +.Fn gtime +system call (exposed as +.Fn time +in userland). +.Fn time +could have been implemented as a wrapper around +.Fn ftime , +but that wasn't done. +.Pp +.Bx 4.1c +implemented a higher-precision time function +.Fn gettimeofday +to replace +.Fn ftime +and reimplemented +.Fn time +in terms of that. +.Pp +Since +.Fx 9 +the implementation of +.Fn time +uses +.Fn clock_gettime "CLOCK_SECOND" +instead of +.Fn gettimeofday +for performance reasons. +.Sh BUGS +Neither +.St -isoC-99 +nor +.St -p1003.1-2001 +requires +.Fn time +to set +.Va errno +on failure; thus, it is impossible for an application to distinguish +the valid time value \-1 (representing the last UTC second of 1969) +from the error return value. +.Pp +Systems conforming to earlier versions of the C and POSIX +standards (including older versions of +.Fx ) +did not set +.No \&* Ns Va tloc +in the error case. diff --git a/lib/libc/gen/time.c b/lib/libc/gen/time.c new file mode 100644 index 000000000000..3f26c937d15b --- /dev/null +++ b/lib/libc/gen/time.c @@ -0,0 +1,48 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1983, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/time.h> + +time_t +time(time_t *t) +{ + struct timespec tt; + time_t retval; + + if (clock_gettime(CLOCK_SECOND, &tt) < 0) + retval = -1; + else + retval = tt.tv_sec; + if (t != NULL) + *t = retval; + return (retval); +} diff --git a/lib/libc/gen/times.3 b/lib/libc/gen/times.3 new file mode 100644 index 000000000000..71449767b551 --- /dev/null +++ b/lib/libc/gen/times.3 @@ -0,0 +1,142 @@ +.\" Copyright (c) 1990, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd December 1, 2008 +.Dt TIMES 3 +.Os +.Sh NAME +.Nm times +.Nd process times +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/times.h +.Ft clock_t +.Fn times "struct tms *tp" +.Sh DESCRIPTION +.Bf -symbolic +This interface is obsoleted by +.Xr getrusage 2 +and +.Xr gettimeofday 2 . +.Ef +.Pp +The +.Fn times +function returns the value of time in +.Dv CLK_TCK Ns 's +of a second since the system startup time. +The current value of +.Dv CLK_TCK , +the frequency of the statistics clock in ticks per second, may be +obtained through the +.Xr sysconf 3 +interface. +.Pp +It also fills in the structure pointed to by +.Fa tp +with time-accounting information. +.Pp +The +.Vt tms +structure is defined as follows: +.Bd -literal -offset indent +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; +.Ed +.Pp +The elements of this structure are defined as follows: +.Bl -tag -width ".Va tms_cutime" +.It Va tms_utime +The +.Tn CPU +time charged for the execution of user instructions. +.It Va tms_stime +The +.Tn CPU +time charged for execution by the system on behalf of +the process. +.It Va tms_cutime +The sum of the +.Va tms_utime Ns s +and +.Va tms_cutime Ns s +of the child processes. +.It Va tms_cstime +The sum of the +.Fa tms_stime Ns s +and +.Fa tms_cstime Ns s +of the child processes. +.El +.Pp +All times are in +.Dv CLK_TCK Ns 's +of a second. +.Pp +The times of a terminated child process are included in the +.Va tms_cutime +and +.Va tms_cstime +elements of the parent when one of the +.Xr wait 2 +functions returns the process ID of the terminated child to the parent. +If an error occurs, +.Fn times +returns the value +.Pq Po Vt clock_t Pc Ns \-1 , +and sets +.Va errno +to indicate the error. +.Sh ERRORS +The +.Fn times +function +may fail and set the global variable +.Va errno +for any of the errors specified for the library +routines +.Xr getrusage 2 +and +.Xr gettimeofday 2 . +.Sh SEE ALSO +.Xr time 1 , +.Xr getrusage 2 , +.Xr gettimeofday 2 , +.Xr wait 2 , +.Xr sysconf 3 , +.Xr clocks 7 +.Sh STANDARDS +The +.Fn times +function +conforms to +.St -p1003.1-88 . diff --git a/lib/libc/gen/times.c b/lib/libc/gen/times.c new file mode 100644 index 000000000000..b609faedc7a1 --- /dev/null +++ b/lib/libc/gen/times.c @@ -0,0 +1,62 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/times.h> +#include <sys/resource.h> + +/* + * Convert usec to clock ticks; could do (usec * CLK_TCK) / 1000000, + * but this would overflow if we switch to nanosec. + */ +#define CONVTCK(r) (r.tv_sec * CLK_TCK + r.tv_usec / (1000000 / CLK_TCK)) + +clock_t +times(struct tms *tp) +{ + struct rusage ru; + struct timespec t; + clock_t c; + + if (getrusage(RUSAGE_SELF, &ru) < 0) + return ((clock_t)-1); + tp->tms_utime = CONVTCK(ru.ru_utime); + tp->tms_stime = CONVTCK(ru.ru_stime); + if (getrusage(RUSAGE_CHILDREN, &ru) < 0) + return ((clock_t)-1); + tp->tms_cutime = CONVTCK(ru.ru_utime); + tp->tms_cstime = CONVTCK(ru.ru_stime); + if (clock_gettime(CLOCK_MONOTONIC, &t)) + return ((clock_t)-1); + c = t.tv_sec * CLK_TCK + t.tv_nsec / (1000000000 / CLK_TCK); + return (c); +} diff --git a/lib/libc/gen/timespec_get.3 b/lib/libc/gen/timespec_get.3 new file mode 100644 index 000000000000..7edf4fe17c30 --- /dev/null +++ b/lib/libc/gen/timespec_get.3 @@ -0,0 +1,97 @@ +.\" $NetBSD: timespec_get.3,v 1.2 2016/10/04 10:46:40 wiz Exp $ +.\" +.\" Copyright (c) 2016 The NetBSD Foundation, Inc. +.\" All rights reserved. +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Kamil Rytarowski. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd August 21, 2023 +.Dt TIMESPEC_GET 3 +.Os +.Sh NAME +.Nm timespec_get +.Nd get current calendar time +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In time.h +.Ft int +.Fn timespec_get "struct timespec *ts" "int base" +.Sh DESCRIPTION +The +.Nm +function sets the interval pointed to by +.Fa ts +to hold the current calendar time based on the specified time base in +.Fa base . +.Pp +The base +.Dv TIME_UTC +returns the time since the epoch. +This time is expressed in seconds and nanoseconds since midnight (0 hour), January 1, 1970. +In +.Fx , +this corresponds to +.Dv CLOCK_REALTIME . +.Pp +The base +.Dv TIME_MONOTONIC +returns a monotonically-increasing time since an unspecified point in the past. +In +.Fx , +this corresponds to +.Dv CLOCK_MONOTONIC . +.Sh RETURN VALUES +The +.Nm +function returns the passed value of +.Fa base +if successful, otherwise +.Dv 0 +on failure. +.Sh SEE ALSO +.Xr clock_gettime 2 , +.Xr gettimeofday 2 , +.Xr time 3 , +.Xr timespec_getres 3 +.Sh STANDARDS +The +.Nm +function with a +.Fa base +of +.Dv TIME_UTC +conforms to +.St -isoC-2011 . +.\" The +.\" .Dv TIME_MONOTONIC +.\" base conforms to +.\" -isoC-2023 . +.Sh HISTORY +This interface first appeared in +.Fx 12 . +.Sh AUTHORS +.An Kamil Rytarowski Aq Mt kamil@NetBSD.org +.An Warner Losh Aq Mt imp@FreeBSD.org diff --git a/lib/libc/gen/timespec_get.c b/lib/libc/gen/timespec_get.c new file mode 100644 index 000000000000..96845d545048 --- /dev/null +++ b/lib/libc/gen/timespec_get.c @@ -0,0 +1,56 @@ +/* $NetBSD: timespec_get.c,v 1.2 2016/10/04 12:48:15 christos Exp $ */ + +/*- + * Copyright (c) 2016 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Kamil Rytarowski. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__RCSID("$NetBSD: timespec_get.c,v 1.2 2016/10/04 12:48:15 christos Exp $"); +#include <time.h> + +/* ISO/IEC 9899:201x 7.27.2.5 The timespec_get function */ + +int +timespec_get(struct timespec *ts, int base) +{ + + switch (base) { + case TIME_UTC: + if (clock_gettime(CLOCK_REALTIME, ts) == -1) + return 0; + break; + case TIME_MONOTONIC: + if (clock_gettime(CLOCK_MONOTONIC, ts) == -1) + return 0; + break; + default: + return 0; + } + + return base; +} diff --git a/lib/libc/gen/timespec_getres.3 b/lib/libc/gen/timespec_getres.3 new file mode 100644 index 000000000000..e00af6758f1a --- /dev/null +++ b/lib/libc/gen/timespec_getres.3 @@ -0,0 +1,51 @@ +.\"- +.\" Copyright (c) 2023 Dag-Erling Smørgrav +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd August 21, 2023 +.Dt TIMESPEC_GETRES 3 +.Os +.Sh NAME +.Nm timespec_getres +.Nd get clock resolution +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In time.h +.Ft int +.Fn timespec_getres "struct timespec *ts" "int base" +.Sh DESCRIPTION +If +.Fa ts +is non-null and +.Fa base +refers to a supported time base as described in +.Xr timespec_get 3 , +the +.Nm +function fills in the structure pointed to by +.Fa ts +to reflect the resolution of that time base. +.Sh RETURN VALUES +The +.Nm +function returns the value of +.Fa base +if successful and zero otherwise. +.Sh SEE ALSO +.Xr clock_getres 2 , +.Xr timespec_get 3 +.\" .Sh STANDARDS +.\" The +.\" .Nm +.\" function conforms to +.\" .St -isoC-2023 . +.Sh HISTORY +This interface first appeared in +.Fx 14 . +.Sh AUTHORS +The +.Nm +function and this manual page were written by +.An Dag-Erling Sm\(/orgrav Aq Mt des@FreeBSD.org . diff --git a/lib/libc/gen/timespec_getres.c b/lib/libc/gen/timespec_getres.c new file mode 100644 index 000000000000..4977d22cf910 --- /dev/null +++ b/lib/libc/gen/timespec_getres.c @@ -0,0 +1,24 @@ +/*- + * Copyright (c) 2023 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <time.h> + +int +timespec_getres(struct timespec *ts, int base) +{ + + switch (base) { + case TIME_UTC: + if (clock_getres(CLOCK_REALTIME, ts) == 0) + return (base); + break; + case TIME_MONOTONIC: + if (clock_getres(CLOCK_MONOTONIC, ts) == 0) + return (base); + break; + } + return (0); +} diff --git a/lib/libc/gen/timezone.c b/lib/libc/gen/timezone.c new file mode 100644 index 000000000000..2809067eb8d8 --- /dev/null +++ b/lib/libc/gen/timezone.c @@ -0,0 +1,126 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#define TZ_MAX_CHARS 255 + +static char *_tztab(int, int); + +/* + * timezone -- + * The arguments are the number of minutes of time you are westward + * from Greenwich and whether DST is in effect. It returns a string + * giving the name of the local timezone. Should be replaced, in the + * application code, by a call to localtime. + */ + +static char czone[TZ_MAX_CHARS]; /* space for zone name */ + +char * +__timezone_compat(int zone, int dst) +{ + char *beg, + *end; + + if ( (beg = getenv("TZNAME")) ) { /* set in environment */ + if ((end = strchr(beg, ','))) { /* "PST,PDT" */ + if (dst) + return(++end); + *end = '\0'; + (void)strncpy(czone,beg,sizeof(czone) - 1); + czone[sizeof(czone) - 1] = '\0'; + *end = ','; + return(czone); + } + return(beg); + } + return(_tztab(zone,dst)); /* default: table or created zone */ +} +__sym_compat(timezone, __timezone_compat, FBSD_1.0); + +static struct zone { + int offset; + char *stdzone; + char *dlzone; +} zonetab[] = { + {-1*60, "MET", "MET DST"}, /* Middle European */ + {-2*60, "EET", "EET DST"}, /* Eastern European */ + {4*60, "AST", "ADT"}, /* Atlantic */ + {5*60, "EST", "EDT"}, /* Eastern */ + {6*60, "CST", "CDT"}, /* Central */ + {7*60, "MST", "MDT"}, /* Mountain */ + {8*60, "PST", "PDT"}, /* Pacific */ +#ifdef notdef + /* there's no way to distinguish this from WET */ + {0, "GMT", 0}, /* Greenwich */ +#endif + {0*60, "WET", "WET DST"}, /* Western European */ + {-10*60,"EST", "EST"}, /* Aust: Eastern */ + {-10*60+30,"CST", "CST"}, /* Aust: Central */ + {-8*60, "WST", 0}, /* Aust: Western */ + {-1} +}; + +/* + * _tztab -- + * check static tables or create a new zone name; broken out so that + * we can make a guess as to what the zone is if the standard tables + * aren't in place in /etc. DO NOT USE THIS ROUTINE OUTSIDE OF THE + * STANDARD LIBRARY. + */ +static char * +_tztab(int zone, int dst) +{ + struct zone *zp; + char sign; + + for (zp = zonetab; zp->offset != -1;++zp) /* static tables */ + if (zp->offset == zone) { + if (dst && zp->dlzone) + return(zp->dlzone); + if (!dst && zp->stdzone) + return(zp->stdzone); + } + + if (zone < 0) { /* create one */ + zone = -zone; + sign = '+'; + } + else + sign = '-'; + (void)snprintf(czone, sizeof(czone), + "GMT%c%d:%02d",sign,zone / 60,zone % 60); + return(czone); +} diff --git a/lib/libc/gen/tls.c b/lib/libc/gen/tls.c new file mode 100644 index 000000000000..b26b13d45589 --- /dev/null +++ b/lib/libc/gen/tls.c @@ -0,0 +1,450 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2004 Doug Rabson + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + * Define stubs for TLS internals so that programs and libraries can + * link. These functions will be replaced by functional versions at + * runtime from ld-elf.so.1. + */ + +#include <sys/param.h> +#include <stdlib.h> +#include <string.h> +#include <elf.h> +#include <unistd.h> + +#include "rtld.h" +#include "libc_private.h" + +#define tls_assert(cond) ((cond) ? (void) 0 : \ + (tls_msg(#cond ": assert failed: " __FILE__ ":" \ + __XSTRING(__LINE__) "\n"), abort())) +#define tls_msg(s) write(STDOUT_FILENO, s, strlen(s)) + +/* Provided by jemalloc to avoid bootstrapping issues. */ +void *__je_bootstrap_malloc(size_t size); +void *__je_bootstrap_calloc(size_t num, size_t size); +void __je_bootstrap_free(void *ptr); + +__weak_reference(__libc_allocate_tls, _rtld_allocate_tls); +__weak_reference(__libc_free_tls, _rtld_free_tls); + +#ifdef __i386__ + +__weak_reference(___libc_tls_get_addr, ___tls_get_addr); +__attribute__((__regparm__(1))) void * ___libc_tls_get_addr(void *); + +#endif + +void * __libc_tls_get_addr(void *); +__weak_reference(__libc_tls_get_addr, __tls_get_addr); + +void *_rtld_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); +void _rtld_free_tls(void *tls, size_t tcbsize, size_t tcbalign); +void *__libc_allocate_tls(void *oldtls, size_t tcbsize, size_t tcbalign); +void __libc_free_tls(void *tls, size_t tcbsize, size_t tcbalign); + +#ifndef PIC + +static size_t libc_tls_static_space; +static size_t libc_tls_init_size; +static size_t libc_tls_init_align; +static void *libc_tls_init; +#endif + +void * +__libc_tls_get_addr(void *vti) +{ + struct dtv *dtv; + tls_index *ti; + + dtv = _tcb_get()->tcb_dtv; + ti = vti; + return (dtv->dtv_slots[ti->ti_module - 1].dtvs_tls + + (ti->ti_offset + TLS_DTV_OFFSET)); +} + +#ifdef __i386__ + +/* GNU ABI */ + +__attribute__((__regparm__(1))) +void * +___libc_tls_get_addr(void *vti) +{ + return (__libc_tls_get_addr(vti)); +} + +#endif + +#ifndef PIC + +static void * +libc_malloc_aligned(size_t size, size_t align) +{ + void *mem, *res; + + if (align < sizeof(void *)) + align = sizeof(void *); + + mem = __je_bootstrap_malloc(size + sizeof(void *) + align - 1); + if (mem == NULL) + return (NULL); + res = (void *)roundup2((uintptr_t)mem + sizeof(void *), align); + *(void **)((uintptr_t)res - sizeof(void *)) = mem; + return (res); +} + +static void +libc_free_aligned(void *ptr) +{ + void *mem; + uintptr_t x; + + if (ptr == NULL) + return; + + x = (uintptr_t)ptr; + x -= sizeof(void *); + mem = *(void **)x; + __je_bootstrap_free(mem); +} + +#ifdef TLS_VARIANT_I + +/* + * There are two versions of variant I of TLS + * + * - ARM and aarch64 uses original variant I as is described in [1] and [2], + * where TP points to start of TCB followed by aligned TLS segment. + * Both TCB and TLS must be aligned to alignment of TLS section. The TCB[0] + * points to DTV vector and DTV values are real addresses (without bias). + * Note: for Local Exec TLS Model, the offsets from TP (TCB in this case) to + * TLS variables are computed by linker, so we cannot overalign TLS section. + * + * - PowerPC and RISC-V use modified version of variant I, described in [3] + * where TP points (with bias) to TLS and TCB immediately precedes TLS without + * any alignment gap[4]. Only TLS should be aligned. The TCB[0] points to DTV + * vector and DTV values are biased by constant value (TLS_DTV_OFFSET) from + * real addresses. However, like RTLD, we don't actually bias the DTV values, + * instead we compensate in __tls_get_addr for ti_offset's bias. + * + * [1] Ulrich Drepper: ELF Handling for Thread-Local Storage + * www.akkadia.org/drepper/tls.pdf + * + * [2] ARM IHI 0045E: Addenda to, and Errata in, the ABI for the ARM(r) + * Architecture + * infocenter.arm.com/help/topic/com.arm.doc.ihi0045e/IHI0045E_ABI_addenda.pdf + * + * [3] OpenPOWER: Power Architecture 64-Bit ELF V2 ABI Specification + * https://members.openpowerfoundation.org/document/dl/576 + * + * [4] Its unclear if "without any alignment gap" is hard ABI requirement, + * but we must follow this rule due to suboptimal _tcb_set() + * (aka <ARCH>_SET_TP) implementation. This function doesn't expect TP but + * TCB as argument. + */ + +/* + * Return pointer to allocated TLS block + */ +static void * +get_tls_block_ptr(void *tcb, size_t tcbsize) +{ + size_t extra_size, post_size, pre_size, tls_block_size; + + /* Compute fragments sizes. */ + extra_size = tcbsize - TLS_TCB_SIZE; +#if defined(__aarch64__) || defined(__arm__) + post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; +#else + post_size = 0; +#endif + tls_block_size = tcbsize + post_size; + pre_size = roundup2(tls_block_size, libc_tls_init_align) - + tls_block_size; + + return ((char *)tcb - pre_size - extra_size); +} + +/* + * Free Static TLS using the Variant I method. The tcbsize + * and tcbalign parameters must be the same as those used to allocate + * the block. + */ +void +__libc_free_tls(void *tcb, size_t tcbsize, size_t tcbalign __unused) +{ + struct dtv *dtv; + + dtv = ((struct tcb *)tcb)->tcb_dtv; + __je_bootstrap_free(dtv); + libc_free_aligned(get_tls_block_ptr(tcb, tcbsize)); +} + +/* + * Allocate Static TLS using the Variant I method. + * + * To handle all above requirements, we setup the following layout for + * TLS block: + * (whole memory block is aligned with MAX(TLS_TCB_ALIGN, tls_init_align)) + * + * +----------+--------------+--------------+-----------+------------------+ + * | pre gap | extended TCB | TCB | post gap | TLS segment | + * | pre_size | extra_size | TLS_TCB_SIZE | post_size | tls_static_space | + * +----------+--------------+--------------+-----------+------------------+ + * + * where: + * extra_size is tcbsize - TLS_TCB_SIZE + * post_size is used to adjust TCB to TLS alignment for first version of TLS + * layout and is always 0 for second version. + * pre_size is used to adjust TCB alignment for first version and to adjust + * TLS alignment for second version. + * + */ +void * +__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) +{ + struct dtv *dtv; + struct tcb *tcb; + char *tls_block, *tls; + size_t extra_size, maxalign, post_size, pre_size, tls_block_size; + + if (oldtcb != NULL && tcbsize == TLS_TCB_SIZE) + return (oldtcb); + + tls_assert(tcbalign >= TLS_TCB_ALIGN); + maxalign = MAX(tcbalign, libc_tls_init_align); + + /* Compute fragmets sizes. */ + extra_size = tcbsize - TLS_TCB_SIZE; +#if defined(__aarch64__) || defined(__arm__) + post_size = roundup2(TLS_TCB_SIZE, libc_tls_init_align) - TLS_TCB_SIZE; +#else + post_size = 0; +#endif + tls_block_size = tcbsize + post_size; + pre_size = roundup2(tls_block_size, libc_tls_init_align) - + tls_block_size; + tls_block_size += pre_size + libc_tls_static_space; + + /* Allocate whole TLS block */ + tls_block = libc_malloc_aligned(tls_block_size, maxalign); + if (tls_block == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } + memset(tls_block, 0, tls_block_size); + tcb = (struct tcb *)(tls_block + pre_size + extra_size); + tls = (char *)tcb + TLS_TCB_SIZE + post_size; + + if (oldtcb != NULL) { + memcpy(tls_block, get_tls_block_ptr(oldtcb, tcbsize), + tls_block_size); + libc_free_aligned(oldtcb); + + /* Adjust the DTV. */ + dtv = tcb->tcb_dtv; + dtv->dtv_slots[0].dtvs_tls = tls; + } else { + dtv = __je_bootstrap_malloc(sizeof(struct dtv) + + sizeof(struct dtv_slot)); + if (dtv == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } + /* Build the DTV. */ + tcb->tcb_dtv = dtv; + dtv->dtv_gen = 1; /* Generation. */ + dtv->dtv_size = 1; /* Segments count. */ + dtv->dtv_slots[0].dtvs_tls = tls; + + if (libc_tls_init_size > 0) + memcpy(tls, libc_tls_init, libc_tls_init_size); + } + + return (tcb); +} + +#endif + +#ifdef TLS_VARIANT_II + +/* + * Free Static TLS using the Variant II method. + */ +void +__libc_free_tls(void *tcb, size_t tcbsize __unused, size_t tcbalign) +{ + size_t size; + struct dtv *dtv; + uintptr_t tlsstart, tlsend; + + /* + * Figure out the size of the initial TLS block so that we can + * find stuff which ___tls_get_addr() allocated dynamically. + */ + tcbalign = MAX(tcbalign, libc_tls_init_align); + size = roundup2(libc_tls_static_space, tcbalign); + + dtv = ((struct tcb *)tcb)->tcb_dtv; + tlsend = (uintptr_t)tcb; + tlsstart = tlsend - size; + libc_free_aligned((void*)tlsstart); + __je_bootstrap_free(dtv); +} + +/* + * Allocate Static TLS using the Variant II method. + */ +void * +__libc_allocate_tls(void *oldtcb, size_t tcbsize, size_t tcbalign) +{ + size_t size; + char *tls_block, *tls; + struct dtv *dtv; + struct tcb *tcb; + + tcbalign = MAX(tcbalign, libc_tls_init_align); + size = roundup2(libc_tls_static_space, tcbalign); + + if (tcbsize < 2 * sizeof(uintptr_t)) + tcbsize = 2 * sizeof(uintptr_t); + tls_block = libc_malloc_aligned(size + tcbsize, tcbalign); + if (tls_block == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } + memset(tls_block, 0, size + tcbsize); + dtv = __je_bootstrap_malloc(sizeof(struct dtv) + + sizeof(struct dtv_slot)); + if (dtv == NULL) { + tls_msg("__libc_allocate_tls: Out of memory.\n"); + abort(); + } + + tcb = (struct tcb *)(tls_block + size); + tls = (char *)tcb - libc_tls_static_space; + tcb->tcb_self = tcb; + tcb->tcb_dtv = dtv; + + dtv->dtv_gen = 1; + dtv->dtv_size = 1; + dtv->dtv_slots[0].dtvs_tls = tls; + + if (oldtcb != NULL) { + /* + * Copy the static TLS block over whole. + */ + memcpy(tls, (const char *)oldtcb - libc_tls_static_space, + libc_tls_static_space); + + /* + * We assume that this block was the one we created with + * allocate_initial_tls(). + */ + _rtld_free_tls(oldtcb, 2 * sizeof(uintptr_t), + sizeof(uintptr_t)); + } else { + memcpy(tls, libc_tls_init, libc_tls_init_size); + memset(tls + libc_tls_init_size, 0, + libc_tls_static_space - libc_tls_init_size); + } + + return (tcb); +} + +#endif /* TLS_VARIANT_II */ + +#else + +void * +__libc_allocate_tls(void *oldtcb __unused, size_t tcbsize __unused, + size_t tcbalign __unused) +{ + return (0); +} + +void +__libc_free_tls(void *tcb __unused, size_t tcbsize __unused, + size_t tcbalign __unused) +{ +} + +#endif /* PIC */ + +void +_init_tls(void) +{ +#ifndef PIC + Elf_Addr *sp; + Elf_Auxinfo *aux, *auxp; + Elf_Phdr *phdr; + size_t phent, phnum; + int i; + void *tls; + + sp = (Elf_Addr *) environ; + while (*sp++ != 0) + ; + aux = (Elf_Auxinfo *) sp; + phdr = NULL; + phent = phnum = 0; + for (auxp = aux; auxp->a_type != AT_NULL; auxp++) { + switch (auxp->a_type) { + case AT_PHDR: + phdr = auxp->a_un.a_ptr; + break; + + case AT_PHENT: + phent = auxp->a_un.a_val; + break; + + case AT_PHNUM: + phnum = auxp->a_un.a_val; + break; + } + } + if (phdr == NULL || phent != sizeof(Elf_Phdr) || phnum == 0) + return; + + for (i = 0; (unsigned) i < phnum; i++) { + if (phdr[i].p_type == PT_TLS) { + libc_tls_static_space = roundup2(phdr[i].p_memsz, + phdr[i].p_align); + libc_tls_init_size = phdr[i].p_filesz; + libc_tls_init_align = phdr[i].p_align; + libc_tls_init = (void *)phdr[i].p_vaddr; + break; + } + } + tls = _rtld_allocate_tls(NULL, TLS_TCB_SIZE, TLS_TCB_ALIGN); + + _tcb_set(tls); +#endif +} diff --git a/lib/libc/gen/trivial-getcontextx.c b/lib/libc/gen/trivial-getcontextx.c new file mode 100644 index 000000000000..b9d4522d96ee --- /dev/null +++ b/lib/libc/gen/trivial-getcontextx.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2011 Konstantin Belousov <kib@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/ucontext.h> +#include <errno.h> +#include <stdlib.h> + +int +__getcontextx_size(void) +{ + + return (sizeof(ucontext_t)); +} + +int +__fillcontextx2(char *ctx) +{ + + return (0); +} + +int +__fillcontextx(char *ctx) +{ + ucontext_t *ucp; + + ucp = (ucontext_t *)ctx; + return (getcontext(ucp)); +} + +__weak_reference(__getcontextx, getcontextx); + +ucontext_t * +__getcontextx(void) +{ + char *ctx; + int error; + + ctx = malloc(__getcontextx_size()); + if (ctx == NULL) + return (NULL); + if (__fillcontextx(ctx) == -1) { + error = errno; + free(ctx); + errno = error; + return (NULL); + } + return ((ucontext_t *)ctx); +} diff --git a/lib/libc/gen/ttyname.3 b/lib/libc/gen/ttyname.3 new file mode 100644 index 000000000000..741b25946ace --- /dev/null +++ b/lib/libc/gen/ttyname.3 @@ -0,0 +1,137 @@ +.\" Copyright (c) 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd July 18, 2014 +.Dt TTYNAME 3 +.Os +.Sh NAME +.Nm ttyname , +.Nm ttyname_r , +.Nm isatty +.Nd get name of associated terminal (tty) from file descriptor +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft char * +.Fn ttyname "int fd" +.Ft int +.Fn ttyname_r "int fd" "char *buf" "size_t len" +.Ft int +.Fn isatty "int fd" +.Sh DESCRIPTION +These functions operate on file descriptors for terminal type devices. +.Pp +The +.Fn isatty +function +determines if the file descriptor +.Fa fd +refers to a valid +terminal type device. +.Pp +The +.Fn ttyname +function +gets the related device name of +a file descriptor for which +.Fn isatty +is true. +.Pp +The +.Fn ttyname +function +returns the name stored in a static buffer which will be overwritten +on subsequent calls. +The +.Fn ttyname_r +function +takes a buffer and length as arguments to avoid this problem. +.Sh RETURN VALUES +The +.Fn isatty +function returns 1 if +.Fa fd +refers to a terminal type device; +otherwise, it returns 0 and may set +.Va errno +to indicate the error. +The +.Fn ttyname +function +returns the null terminated name if the device is found and +.Fn isatty +is true; otherwise +a +.Dv NULL +pointer is returned. +The +.Fn ttyname_r +function returns 0 if successful. +Otherwise an error number is returned. +.Sh ERRORS +These functions may fail if: +.Bl -tag -width Er +.It Bq Er EBADF +The +.Fa fd +argument +is not a valid file descriptor. +.It Bq Er ENOTTY +The file associated with +.Fa fd +is not a terminal. +.El +.Pp +Additionally, +.Fn ttyname_r +may fail if: +.Bl -tag -width Er +.It Bq Er ERANGE +The +.Fa bufsize +argument +is smaller than the length of the string to be returned. +.El +.Sh SEE ALSO +.Xr fdevname 3 , +.Xr ptsname 3 , +.Xr tcgetattr 3 , +.Xr tty 4 +.Sh HISTORY +The +.Fn isatty +and +.Fn ttyname +functions +appeared in +.At v7 . +The +.Fn ttyname_r +function +appeared in +.Fx 6.0 . diff --git a/lib/libc/gen/ttyname.c b/lib/libc/gen/ttyname.c new file mode 100644 index 000000000000..f1e2f401fe5d --- /dev/null +++ b/lib/libc/gen/ttyname.c @@ -0,0 +1,111 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/filio.h> +#include <fcntl.h> +#include <dirent.h> +#include <stdlib.h> +#include <termios.h> +#include <unistd.h> +#include <string.h> +#include <paths.h> +#include <errno.h> +#include "reentrant.h" +#include <ssp/ssp.h> +#include "un-namespace.h" + +#include "libc_private.h" + +static char ttyname_buf[sizeof(_PATH_DEV) + MAXNAMLEN]; + +static once_t ttyname_init_once = ONCE_INITIALIZER; +static thread_key_t ttyname_key; +static int ttyname_keycreated = 0; + +int +__ssp_real(ttyname_r)(int fd, char *buf, size_t len) +{ + size_t used; + + /* Don't write off the end of a zero-length buffer. */ + if (len < 1) + return (ERANGE); + + *buf = '\0'; + + /* Must be a terminal. */ + if (!isatty(fd)) + return (errno); + /* Must have enough room */ + if (len <= sizeof(_PATH_DEV)) + return (ERANGE); + + strcpy(buf, _PATH_DEV); + used = strlen(buf); + if (fdevname_r(fd, buf + used, len - used) == NULL) + return (errno == EINVAL ? ERANGE : errno); + return (0); +} + +static void +ttyname_keycreate(void) +{ + ttyname_keycreated = (thr_keycreate(&ttyname_key, free) == 0); +} + +char * +ttyname(int fd) +{ + char *buf; + + if (thr_main() != 0) + buf = ttyname_buf; + else { + if (thr_once(&ttyname_init_once, ttyname_keycreate) != 0 || + !ttyname_keycreated) + return (NULL); + if ((buf = thr_getspecific(ttyname_key)) == NULL) { + if ((buf = malloc(sizeof ttyname_buf)) == NULL) + return (NULL); + if (thr_setspecific(ttyname_key, buf) != 0) { + free(buf); + return (NULL); + } + } + } + + if (ttyname_r(fd, buf, sizeof ttyname_buf) != 0) + return (NULL); + return (buf); +} diff --git a/lib/libc/gen/ttyslot.c b/lib/libc/gen/ttyslot.c new file mode 100644 index 000000000000..a57b18dcf030 --- /dev/null +++ b/lib/libc/gen/ttyslot.c @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> + +int __ttyslot(void); + +int +__ttyslot(void) +{ + + return (0); +} + +__sym_compat(ttyslot, __ttyslot, FBSD_1.0); diff --git a/lib/libc/gen/ualarm.3 b/lib/libc/gen/ualarm.3 new file mode 100644 index 000000000000..dfd9ddd5f434 --- /dev/null +++ b/lib/libc/gen/ualarm.3 @@ -0,0 +1,94 @@ +.\" Copyright (c) 1986, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd April 19, 1994 +.Dt UALARM 3 +.Os +.Sh NAME +.Nm ualarm +.Nd schedule signal after specified time +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft useconds_t +.Fn ualarm "useconds_t microseconds" "useconds_t interval" +.Sh DESCRIPTION +.Bf -symbolic +This is a simplified interface to +.Xr setitimer 2 . +.Ef +.Pp +The +.Fn ualarm +function +waits a count of +.Fa microseconds +before asserting the terminating signal +.Dv SIGALRM . +System activity or time used in processing the call may cause a slight +delay. +.Pp +If the +.Fa interval +argument is non-zero, the +.Dv SIGALRM +signal will be sent +to the process every +.Fa interval +microseconds after the timer expires (e.g.\& after +.Fa microseconds +number of microseconds have passed). +.Pp +Due to +.Xr setitimer 2 +restriction the maximum number of +.Fa microseconds +and +.Fa interval +is limited to 100,000,000,000,000 +(in case this value fits in the unsigned integer). +.Sh RETURN VALUES +When the signal has successfully been caught, +.Fn ualarm +returns the amount of time left on the clock. +.Sh NOTES +A microsecond is 0.000001 seconds. +.Sh SEE ALSO +.Xr getitimer 2 , +.Xr setitimer 2 , +.Xr sigaction 2 , +.Xr sigsuspend 2 , +.Xr alarm 3 , +.Xr signal 3 , +.Xr sleep 3 , +.Xr usleep 3 +.Sh HISTORY +The +.Fn ualarm +function appeared in +.Bx 4.3 . diff --git a/lib/libc/gen/ualarm.c b/lib/libc/gen/ualarm.c new file mode 100644 index 000000000000..44e77252202f --- /dev/null +++ b/lib/libc/gen/ualarm.c @@ -0,0 +1,56 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1985, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/time.h> +#include <unistd.h> + +#define USPS 1000000 /* # of microseconds in a second */ + +/* + * Generate a SIGALRM signal in ``usecs'' microseconds. + * If ``reload'' is non-zero, keep generating SIGALRM + * every ``reload'' microseconds after the first signal. + */ +useconds_t +ualarm(useconds_t usecs, useconds_t reload) +{ + struct itimerval new, old; + + new.it_interval.tv_usec = reload % USPS; + new.it_interval.tv_sec = reload / USPS; + + new.it_value.tv_usec = usecs % USPS; + new.it_value.tv_sec = usecs / USPS; + + if (setitimer(ITIMER_REAL, &new, &old) == 0) + return (old.it_value.tv_sec * USPS + old.it_value.tv_usec); + return (-1); +} diff --git a/lib/libc/gen/ucontext.3 b/lib/libc/gen/ucontext.3 new file mode 100644 index 000000000000..4166049957db --- /dev/null +++ b/lib/libc/gen/ucontext.3 @@ -0,0 +1,121 @@ +.\" Copyright (c) 2002 Packet Design, LLC. +.\" All rights reserved. +.\" +.\" Subject to the following obligations and disclaimer of warranty, +.\" use and redistribution of this software, in source or object code +.\" forms, with or without modifications are expressly permitted by +.\" Packet Design; provided, however, that: +.\" +.\" (i) Any and all reproductions of the source or object code +.\" must include the copyright notice above and the following +.\" disclaimer of warranties; and +.\" (ii) No rights are granted, in any manner or form, to use +.\" Packet Design trademarks, including the mark "PACKET DESIGN" +.\" on advertising, endorsements, or otherwise except as such +.\" appears in the above copyright notice or in the software. +.\" +.\" THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND +.\" TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO +.\" REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING +.\" THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED +.\" WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, +.\" OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE, +.\" OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS +.\" OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, +.\" RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE +.\" LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE +.\" OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT, +.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL +.\" DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF +.\" USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF +.\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +.\" THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF +.\" THE POSSIBILITY OF SUCH DAMAGE. +.\" +.Dd March 23, 2020 +.Dt UCONTEXT 3 +.Os +.Sh NAME +.Nm ucontext +.Nd user thread context +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In ucontext.h +.Sh DESCRIPTION +The +.Vt ucontext_t +type is a structure type suitable for holding the context for a user +thread of execution. +A thread's context includes its stack, saved registers, and list of +blocked signals. +.Pp +The +.Vt ucontext_t +structure contains at least these fields: +.Pp +.Bl -tag -width ".Va mcontext_t\ \ uc_mcontext" -offset 3n -compact +.It Va "ucontext_t *uc_link" +context to assume when this one returns +.It Va "sigset_t uc_sigmask" +signals being blocked +.It Va "stack_t uc_stack" +stack area +.It Va "mcontext_t uc_mcontext" +saved registers +.El +.Pp +The +.Va uc_link +field points to the context to resume when this context's entry point +function returns. +If +.Va uc_link +is equal to +.Dv NULL , +then the process exits when this context returns. +.Pp +The +.Va uc_mcontext +field is machine-dependent and should be treated as opaque by +portable applications. +.Pp +The following functions are defined to manipulate +.Vt ucontext_t +structures: +.Pp +.Bl -item -offset 3n -compact +.It +.Ft int +.Fn getcontext "ucontext_t *" ; +.It +.Ft "ucontext_t *" +.Fn getcontextx "void" ; +.It +.Ft int +.Fn setcontext "const ucontext_t *" ; +.It +.Ft void +.Fn makecontext "ucontext_t *" "void \*[lp]*\*[rp]\*[lp]void\*[rp]" int ... ; +.It +.Ft int +.Fn swapcontext "ucontext_t *" "const ucontext_t *" ; +.El +.Sh SEE ALSO +.Xr sigaltstack 2 , +.Xr getcontext 3 , +.Xr getcontextx 3 , +.Xr makecontext 3 +.Sh STANDARDS +The +.Vt ucontext_t +type conforms to +.St -xsh5 +and +.St -p1003.1-2001 . +The +.St -p1003.1-2008 +revision removed the +.Vt ucontext_t +from the specification. diff --git a/lib/libc/gen/uexterr_format.c b/lib/libc/gen/uexterr_format.c new file mode 100644 index 000000000000..e8ddfbd578e3 --- /dev/null +++ b/lib/libc/gen/uexterr_format.c @@ -0,0 +1,35 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 The FreeBSD Foundation + * All rights reserved. + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + */ + +#include <sys/types.h> +#include <sys/exterrvar.h> +#include <exterr.h> +#include <stdio.h> +#include <string.h> + +int +__uexterr_format(const struct uexterror *ue, char *buf, size_t bufsz) +{ + if (bufsz > UEXTERROR_MAXLEN) + bufsz = UEXTERROR_MAXLEN; + if (ue->error == 0) { + strlcpy(buf, "", bufsz); + return (0); + } + if (ue->msg[0] == '\0') { + snprintf(buf, bufsz, + "errno %d category %u (src line %u) p1 %#jx p2 %#jx", + ue->error, ue->cat, ue->src_line, + (uintmax_t)ue->p1, (uintmax_t)ue->p2); + } else { + strlcpy(buf, ue->msg, bufsz); + } + return (0); +} diff --git a/lib/libc/gen/uexterr_gettext.c b/lib/libc/gen/uexterr_gettext.c new file mode 100644 index 000000000000..5b8a5cd17a48 --- /dev/null +++ b/lib/libc/gen/uexterr_gettext.c @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2025 The FreeBSD Foundation + * All rights reserved. + * + * This software were developed by Konstantin Belousov <kib@FreeBSD.org> + * under sponsorship from the FreeBSD Foundation. + */ + +#define _WANT_P_OSREL +#include <sys/param.h> +#include <sys/exterrvar.h> +#include <exterr.h> +#include <string.h> +#include "libc_private.h" + +static struct uexterror uexterr = { + .ver = UEXTERROR_VER, +}; + +int __getosreldate(void); + +static void uexterr_ctr(void) __attribute__((constructor)); +static void +uexterr_ctr(void) +{ + if (__getosreldate() >= P_OSREL_EXTERRCTL) + exterrctl(EXTERRCTL_ENABLE, 0, &uexterr); +} + +int +__libc_uexterr_gettext(char *buf, size_t bufsz) +{ + return (__uexterr_format(&uexterr, buf, bufsz)); +} + +int +uexterr_gettext(char *buf, size_t bufsz) +{ + return (((int (*)(char *, size_t)) + __libc_interposing[INTERPOS_uexterr_gettext])(buf, bufsz)); +} diff --git a/lib/libc/gen/ulimit.3 b/lib/libc/gen/ulimit.3 new file mode 100644 index 000000000000..771c40126944 --- /dev/null +++ b/lib/libc/gen/ulimit.3 @@ -0,0 +1,96 @@ +.\" Copyright (c) 2002 Kyle Martin. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd January 4, 2003 +.Dt ULIMIT 3 +.Os +.Sh NAME +.Nm ulimit +.Nd get and set process limits +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In ulimit.h +.Ft long +.Fn ulimit "int cmd" "..." +.Sh DESCRIPTION +The +.Fn ulimit +function will get and set process limits. +Currently this is limited to the maximum file size. +The +.Fa cmd +argument is one of the following: +.Bl -tag -width ".Dv UL_GETFSIZE" +.It Dv UL_GETFSIZE +will return the maximum file size in units of 512 blocks of +the current process. +.It Dv UL_SETFSIZE +will attempt to set the maximum file size of the current +process and its children with the second argument expressed as a long. +.El +.Sh RETURN VALUES +Upon successful completion, +.Fn ulimit +returns the value requested; +otherwise the value \-1 is returned and the global variable +.Va errno +is set to indicate the error. +.Sh ERRORS +The +.Fn ulimit +function will fail if: +.Bl -tag -width Er +.It Bq Er EINVAL +The command specified was invalid. +.It Bq Er EPERM +The limit specified to +.Fn ulimit +would have raised the maximum limit value, +and the caller is not the super-user. +.El +.Sh SEE ALSO +.Xr getrlimit 2 +.Sh STANDARDS +The +.Fn ulimit +function conforms to +.St -p1003.1-2001 . +.Sh HISTORY +The +.Fn ulimit +function first appeared in +.Fx 5.0 . +.Sh BUGS +The +.Fn ulimit +function provides limited precision for +setting and retrieving process limits. +If there is a need for greater precision than the +type +.Vt long +provides, the +.Xr getrlimit 2 +and +.Xr setrlimit 2 +functions should be considered. diff --git a/lib/libc/gen/ulimit.c b/lib/libc/gen/ulimit.c new file mode 100644 index 000000000000..93231bb86fa8 --- /dev/null +++ b/lib/libc/gen/ulimit.c @@ -0,0 +1,70 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2002 Kyle Martin <mkm@ieee.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <sys/time.h> +#include <sys/resource.h> + +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <ulimit.h> + +long +ulimit(int cmd, ...) +{ + struct rlimit limit; + va_list ap; + rlim_t arg; + + if (cmd == UL_GETFSIZE) { + if (getrlimit(RLIMIT_FSIZE, &limit) == -1) + return (-1); + limit.rlim_cur /= 512; + if (limit.rlim_cur > LONG_MAX) + return (LONG_MAX); + return ((long)limit.rlim_cur); + } else if (cmd == UL_SETFSIZE) { + va_start(ap, cmd); + arg = va_arg(ap, long); + va_end(ap); + if (arg < 0) + arg = LONG_MAX; + if (arg > RLIM_INFINITY / 512) + arg = RLIM_INFINITY / 512; + limit.rlim_max = limit.rlim_cur = arg * 512; + + /* The setrlimit() function sets errno to EPERM if needed. */ + if (setrlimit(RLIMIT_FSIZE, &limit) == -1) + return (-1); + return ((long)arg); + } else { + errno = EINVAL; + return (-1); + } +} diff --git a/lib/libc/gen/uname.3 b/lib/libc/gen/uname.3 new file mode 100644 index 000000000000..ed1596529c4c --- /dev/null +++ b/lib/libc/gen/uname.3 @@ -0,0 +1,114 @@ +.\" Copyright (c) 1994 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd December 2, 2005 +.Dt UNAME 3 +.Os +.Sh NAME +.Nm uname +.Nd get system identification +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In sys/utsname.h +.Ft int +.Fn uname "struct utsname *name" +.Sh DESCRIPTION +The +.Fn uname +function stores +.Dv NUL Ns -terminated +strings of information identifying +the current system into the structure referenced by +.Fa name . +.Pp +The +.Vt utsname +structure is defined in the +.In sys/utsname.h +header file, and contains the following members: +.Bl -tag -width nodenameXXXX -offset indent +.It sysname +Name of the operating system implementation. +.It nodename +Network name of this machine. +.It release +Release level of the operating system. +.It version +Version level of the operating system. +.It machine +Machine hardware platform. +.El +.Sh RETURN VALUES +.Rv -std uname +.Sh ENVIRONMENT +.Bl -tag -width ".Ev UNAME_s" +.It Ev UNAME_s +If the environment variable +.Ev UNAME_s +is set, it will override the +.Va sysname +member. +.It Ev UNAME_r +If the environment variable +.Ev UNAME_r +is set, it will override the +.Va release +member. +.It Ev UNAME_v +If the environment variable +.Ev UNAME_v +is set, it will override the +.Va version +member. +.It Ev UNAME_m +If the environment variable +.Ev UNAME_m +is set, it will override the +.Va machine +member. +.El +.Sh ERRORS +The +.Fn uname +function may fail and set +.Va errno +for any of the errors specified for the library functions +.Xr sysctl 3 . +.Sh SEE ALSO +.Xr uname 1 , +.Xr sysctl 3 +.Sh STANDARDS +The +.Fn uname +function conforms to +.St -p1003.1-88 . +.Sh HISTORY +The +.Fn uname +function first appeared in +.Bx 4.4 . diff --git a/lib/libc/gen/uname.c b/lib/libc/gen/uname.c new file mode 100644 index 000000000000..3a14ae3fefc1 --- /dev/null +++ b/lib/libc/gen/uname.c @@ -0,0 +1,45 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define uname wrapped_uname +#include <sys/param.h> +#include <sys/sysctl.h> +#include <sys/utsname.h> +#include <errno.h> +#undef uname + +int uname(struct utsname *); + +int +uname(struct utsname *name) +{ + return __xuname(32, name); +} diff --git a/lib/libc/gen/unvis-compat.c b/lib/libc/gen/unvis-compat.c new file mode 100644 index 000000000000..4562b8f7a383 --- /dev/null +++ b/lib/libc/gen/unvis-compat.c @@ -0,0 +1,48 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2012 SRI International + * All rights reserved. + * + * This software was developed by SRI International and the University of + * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) + * ("CTSRD"), as part of the DARPA CRASH research programme. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <vis.h> + +#define _UNVIS_END 1 + +int __unvis_44bsd(char *, int, int *, int); + +int +__unvis_44bsd(char *cp, int c, int *astate, int flag) +{ + + if (flag & _UNVIS_END) + flag = (flag & ~_UNVIS_END) ^ UNVIS_END; + return unvis(cp, c, astate, flag); +} + +__sym_compat(unvis, __vis_44bsd, FBSD_1.0); diff --git a/lib/libc/gen/usleep.c b/lib/libc/gen/usleep.c new file mode 100644 index 000000000000..31d5567d562d --- /dev/null +++ b/lib/libc/gen/usleep.c @@ -0,0 +1,52 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1989, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <time.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "libc_private.h" + +int __usleep(useconds_t); + +int +__usleep(useconds_t useconds) +{ + struct timespec time_to_sleep; + + time_to_sleep.tv_nsec = (useconds % 1000000) * 1000; + time_to_sleep.tv_sec = useconds / 1000000; + return (INTERPOS_SYS(nanosleep, &time_to_sleep, NULL)); +} + +__weak_reference(__usleep, usleep); +__weak_reference(__usleep, _usleep); diff --git a/lib/libc/gen/utime.3 b/lib/libc/gen/utime.3 new file mode 100644 index 000000000000..e17fab908497 --- /dev/null +++ b/lib/libc/gen/utime.3 @@ -0,0 +1,91 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd June 9, 2016 +.Dt UTIME 3 +.Os +.Sh NAME +.Nm utime +.Nd set file times +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In utime.h +.Ft int +.Fn utime "const char *file" "const struct utimbuf *timep" +.Sh DESCRIPTION +.Bf -symbolic +This interface is obsoleted by +.Xr utimensat 2 +because it is not accurate to fractions of a second. +.Ef +.Pp +The +.Fn utime +function sets the access and modification times of the named file from +the +.Va actime +and +.Va modtime +fields of the +.Vt "struct utimbuf" +pointed at by +.Fa timep . +.Pp +If the times are specified (the +.Fa timep +argument is +.Pf non- Dv NULL ) +the caller must be the owner of the file or be the super-user. +.Pp +If the times are not specified (the +.Fa timep +argument is +.Dv NULL ) +the caller must be the owner of the file, have permission to write +the file, or be the super-user. +.Sh ERRORS +The +.Fn utime +function may fail and set +.Va errno +for any of the errors specified for the library function +.Xr utimes 2 . +.Sh SEE ALSO +.Xr stat 2 , +.Xr utimensat 2 , +.Xr utimes 2 +.Sh STANDARDS +The +.Fn utime +function conforms to +.St -p1003.1-88 . +.Sh HISTORY +A +.Fn utime +function appeared in +.At v7 . diff --git a/lib/libc/gen/utime.c b/lib/libc/gen/utime.c new file mode 100644 index 000000000000..208c6bdae449 --- /dev/null +++ b/lib/libc/gen/utime.c @@ -0,0 +1,49 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/time.h> + +#include <utime.h> + +int +utime(const char *path, const struct utimbuf *times) +{ + struct timeval tv[2], *tvp; + + if (times) { + tv[0].tv_sec = times->actime; + tv[1].tv_sec = times->modtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + tvp = tv; + } else + tvp = NULL; + return (utimes(path, tvp)); +} diff --git a/lib/libc/gen/utxdb.c b/lib/libc/gen/utxdb.c new file mode 100644 index 000000000000..4c4c73bffea3 --- /dev/null +++ b/lib/libc/gen/utxdb.c @@ -0,0 +1,174 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/endian.h> +#include <sys/param.h> +#include <sys/time.h> +#include <stdlib.h> +#include <string.h> +#include <utmpx.h> +#include "utxdb.h" +#include "un-namespace.h" + +#define UTOF_STRING(ut, fu, field) do { \ + strncpy((fu)->fu_ ## field, (ut)->ut_ ## field, \ + MIN(sizeof (fu)->fu_ ## field, sizeof (ut)->ut_ ## field)); \ +} while (0) +#define UTOF_ID(ut, fu) do { \ + memcpy((fu)->fu_id, (ut)->ut_id, \ + MIN(sizeof (fu)->fu_id, sizeof (ut)->ut_id)); \ +} while (0) +#define UTOF_PID(ut, fu) do { \ + (fu)->fu_pid = htobe32((ut)->ut_pid); \ +} while (0) +#define UTOF_TYPE(ut, fu) do { \ + (fu)->fu_type = (ut)->ut_type; \ +} while (0) +#define UTOF_TV(fu) do { \ + struct timeval tv; \ + gettimeofday(&tv, NULL); \ + (fu)->fu_tv = htobe64((uint64_t)tv.tv_sec * 1000000 + \ + (uint64_t)tv.tv_usec); \ +} while (0) + +void +utx_to_futx(const struct utmpx *ut, struct futx *fu) +{ + + memset(fu, 0, sizeof *fu); + + switch (ut->ut_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + /* Extension: shutdown time. */ + case SHUTDOWN_TIME: + break; + case USER_PROCESS: + UTOF_ID(ut, fu); + UTOF_STRING(ut, fu, user); + UTOF_STRING(ut, fu, line); + /* Extension: host name. */ + UTOF_STRING(ut, fu, host); + UTOF_PID(ut, fu); + break; + case INIT_PROCESS: + UTOF_ID(ut, fu); + UTOF_PID(ut, fu); + break; + case LOGIN_PROCESS: + UTOF_ID(ut, fu); + UTOF_STRING(ut, fu, user); + UTOF_STRING(ut, fu, line); + UTOF_PID(ut, fu); + break; + case DEAD_PROCESS: + UTOF_ID(ut, fu); + UTOF_PID(ut, fu); + break; + default: + fu->fu_type = EMPTY; + return; + } + + UTOF_TYPE(ut, fu); + UTOF_TV(fu); +} + +#define FTOU_STRING(fu, ut, field) do { \ + strncpy((ut)->ut_ ## field, (fu)->fu_ ## field, \ + MIN(sizeof (ut)->ut_ ## field - 1, sizeof (fu)->fu_ ## field)); \ +} while (0) +#define FTOU_ID(fu, ut) do { \ + memcpy((ut)->ut_id, (fu)->fu_id, \ + MIN(sizeof (ut)->ut_id, sizeof (fu)->fu_id)); \ +} while (0) +#define FTOU_PID(fu, ut) do { \ + (ut)->ut_pid = be32toh((fu)->fu_pid); \ +} while (0) +#define FTOU_TYPE(fu, ut) do { \ + (ut)->ut_type = (fu)->fu_type; \ +} while (0) +#define FTOU_TV(fu, ut) do { \ + uint64_t t; \ + t = be64toh((fu)->fu_tv); \ + (ut)->ut_tv.tv_sec = t / 1000000; \ + (ut)->ut_tv.tv_usec = t % 1000000; \ +} while (0) + +struct utmpx * +futx_to_utx(const struct futx *fu) +{ + static _Thread_local struct utmpx *ut; + + if (ut == NULL) { + ut = calloc(1, sizeof *ut); + if (ut == NULL) + return (NULL); + } else + memset(ut, 0, sizeof *ut); + + switch (fu->fu_type) { + case BOOT_TIME: + case OLD_TIME: + case NEW_TIME: + /* Extension: shutdown time. */ + case SHUTDOWN_TIME: + break; + case USER_PROCESS: + FTOU_ID(fu, ut); + FTOU_STRING(fu, ut, user); + FTOU_STRING(fu, ut, line); + /* Extension: host name. */ + FTOU_STRING(fu, ut, host); + FTOU_PID(fu, ut); + break; + case INIT_PROCESS: + FTOU_ID(fu, ut); + FTOU_PID(fu, ut); + break; + case LOGIN_PROCESS: + FTOU_ID(fu, ut); + FTOU_STRING(fu, ut, user); + FTOU_STRING(fu, ut, line); + FTOU_PID(fu, ut); + break; + case DEAD_PROCESS: + FTOU_ID(fu, ut); + FTOU_PID(fu, ut); + break; + default: + ut->ut_type = EMPTY; + return (ut); + } + + FTOU_TYPE(fu, ut); + FTOU_TV(fu, ut); + return (ut); +} diff --git a/lib/libc/gen/utxdb.h b/lib/libc/gen/utxdb.h new file mode 100644 index 000000000000..5b1f35f99fd7 --- /dev/null +++ b/lib/libc/gen/utxdb.h @@ -0,0 +1,61 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef _UTXDB_H_ +#define _UTXDB_H_ + +#include <stdint.h> + +#define _PATH_UTX_ACTIVE "/var/run/utx.active" +#define _PATH_UTX_LASTLOGIN "/var/log/utx.lastlogin" +#define _PATH_UTX_LOG "/var/log/utx.log" + +/* + * Entries in struct futx are ordered by how often they are used. In + * utx.log only entries will be written until the last non-zero byte, + * which means we want to put the hostname at the end. Most primitive + * records only store a ut_type and ut_tv, which means we want to store + * those at the front. + */ + +struct utmpx; + +struct futx { + uint8_t fu_type; + uint64_t fu_tv; + char fu_id[8]; + uint32_t fu_pid; + char fu_user[32]; + char fu_line[16]; + char fu_host[128]; +} __packed; + +void utx_to_futx(const struct utmpx *, struct futx *); +struct utmpx *futx_to_utx(const struct futx *); + +#endif /* !_UTXDB_H_ */ diff --git a/lib/libc/gen/valloc.3 b/lib/libc/gen/valloc.3 new file mode 100644 index 000000000000..063e781e3174 --- /dev/null +++ b/lib/libc/gen/valloc.3 @@ -0,0 +1,72 @@ +.\" Copyright (c) 1980, 1991, 1993 +.\" The Regents of the University of California. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. Neither the name of the University nor the names of its contributors +.\" may be used to endorse or promote products derived from this software +.\" without specific prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd October 30, 2007 +.Dt VALLOC 3 +.Os +.Sh NAME +.Nm valloc +.Nd aligned memory allocation function +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In unistd.h +.Ft void * +.Fn valloc "size_t size" +.Sh DESCRIPTION +The +.Fn valloc +function is obsoleted by +.Xr posix_memalign 3 , +which can be used to request page-aligned allocations. +.Pp +The +.Fn valloc +function +allocates +.Fa size +bytes aligned on a page boundary. +.Sh RETURN VALUES +The +.Fn valloc +function returns +a pointer to the allocated space if successful; otherwise +a null pointer is returned. +.Sh SEE ALSO +.Xr posix_memalign 3 +.Sh HISTORY +The +.Fn valloc +function appeared in +.Bx 3.0 . +.Pp +The +.Fn valloc +function correctly allocated memory that could be deallocated via +.Fn free +starting in +.Fx 7.0 . diff --git a/lib/libc/gen/valloc.c b/lib/libc/gen/valloc.c new file mode 100644 index 000000000000..6f3fd2d2d10c --- /dev/null +++ b/lib/libc/gen/valloc.c @@ -0,0 +1,44 @@ +/*- + * SPDX-License-Identifier: BSD-3-Clause + * + * Copyright (c) 1980, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <stdlib.h> +#include <unistd.h> + +void * +valloc(size_t i) +{ + void *ret; + + if (posix_memalign(&ret, getpagesize(), i) != 0) + ret = NULL; + + return ret; +} diff --git a/lib/libc/gen/wordexp.3 b/lib/libc/gen/wordexp.3 new file mode 100644 index 000000000000..f54d8af3f38c --- /dev/null +++ b/lib/libc/gen/wordexp.3 @@ -0,0 +1,208 @@ +.\" +.\" Copyright (c) 2002 Tim J. Robbins +.\" All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd September 30, 2015 +.Dt WORDEXP 3 +.Os +.Sh NAME +.Nm wordexp +.Nd "perform shell-style word expansions" +.Sh LIBRARY +.Lb libc +.Sh SYNOPSIS +.In wordexp.h +.Ft int +.Fn wordexp "const char * restrict words" "wordexp_t * restrict we" "int flags" +.Ft void +.Fn wordfree "wordexp_t *we" +.Sh DESCRIPTION +The +.Fn wordexp +function performs shell-style word expansion on +.Fa words +and places the list of words into the +.Va we_wordv +member of +.Fa we , +and the number of words into +.Va we_wordc . +.Pp +The +.Fa flags +argument is the bitwise inclusive OR of any of the following constants: +.Bl -tag -width ".Dv WRDE_SHOWERR" +.It Dv WRDE_APPEND +Append the words to those generated by a previous call to +.Fn wordexp . +.It Dv WRDE_DOOFFS +As many +.Dv NULL +pointers as are specified by the +.Va we_offs +member of +.Fa we +are added to the front of +.Va we_wordv . +.It Dv WRDE_NOCMD +Disallow command substitution in +.Fa words . +See the note in +.Sx BUGS +before using this. +.It Dv WRDE_REUSE +The +.Fa we +argument was passed to a previous successful call to +.Fn wordexp +but has not been passed to +.Fn wordfree . +The implementation may reuse the space allocated to it. +.It Dv WRDE_SHOWERR +Do not redirect shell error messages to +.Pa /dev/null . +.It Dv WRDE_UNDEF +Report error on an attempt to expand an undefined shell variable. +.El +.Pp +The +.Vt wordexp_t +structure is defined in +.In wordexp.h +as: +.Bd -literal -offset indent +typedef struct { + size_t we_wordc; /* count of words matched */ + char **we_wordv; /* pointer to list of words */ + size_t we_offs; /* slots to reserve in we_wordv */ +} wordexp_t; +.Ed +.Pp +The +.Fn wordfree +function frees the memory allocated by +.Fn wordexp . +.Sh IMPLEMENTATION NOTES +The +.Fn wordexp +function is implemented using the undocumented +.Ic freebsd_wordexp +shell built-in command. +.Sh RETURN VALUES +The +.Fn wordexp +function returns zero if successful, otherwise it returns one of the following +error codes: +.Bl -tag -width ".Dv WRDE_NOSPACE" +.It Dv WRDE_BADCHAR +The +.Fa words +argument contains one of the following unquoted characters: +.Aq newline , +.Ql | , +.Ql & , +.Ql \&; , +.Ql < , +.Ql > , +.Ql \&( , +.Ql \&) , +.Ql { , +.Ql } . +.It Dv WRDE_BADVAL +An error after successful parsing, +such as an attempt to expand an undefined shell variable with +.Dv WRDE_UNDEF +set in +.Fa flags . +.It Dv WRDE_CMDSUB +An attempt was made to use command substitution and +.Dv WRDE_NOCMD +is set in +.Fa flags . +.It Dv WRDE_NOSPACE +Not enough memory to store the result or +an error during +.Xr fork 2 . +.It Dv WRDE_SYNTAX +Shell syntax error in +.Fa words . +.El +.Pp +The +.Fn wordfree +function returns no value. +.Sh ENVIRONMENT +.Bl -tag -width ".Ev IFS" +.It Ev IFS +Field separator. +.El +.Sh EXAMPLES +Invoke the editor on all +.Pa .c +files in the current directory +and +.Pa /etc/motd +(error checking omitted): +.Bd -literal -offset indent +wordexp_t we; + +wordexp("${EDITOR:-vi} *.c /etc/motd", &we, 0); +execvp(we.we_wordv[0], we.we_wordv); +.Ed +.Sh DIAGNOSTICS +Diagnostic messages from the shell are written to the standard error output +if +.Dv WRDE_SHOWERR +is set in +.Fa flags . +.Sh SEE ALSO +.Xr sh 1 , +.Xr fnmatch 3 , +.Xr glob 3 , +.Xr popen 3 , +.Xr system 3 +.Sh STANDARDS +The +.Fn wordexp +and +.Fn wordfree +functions conform to +.St -p1003.1-2001 . +.Sh BUGS +The current +.Fn wordexp +implementation does not recognize multibyte characters other than UTF-8, since +the shell (which it invokes to perform expansions) does not. +.Sh SECURITY CONSIDERATIONS +Pathname generation may create output that is exponentially larger than the +input size. +.Pp +Although this implementation detects command substitution reliably for +.Dv WRDE_NOCMD , +the attack surface remains fairly large. +Also, some other implementations +(such as older versions of this one) +may execute command substitutions even if +.Dv WRDE_NOCMD +is set. diff --git a/lib/libc/gen/wordexp.c b/lib/libc/gen/wordexp.c new file mode 100644 index 000000000000..f8080c20d121 --- /dev/null +++ b/lib/libc/gen/wordexp.c @@ -0,0 +1,416 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2002 Tim J. Robbins. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "namespace.h" +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <wordexp.h> +#include "un-namespace.h" +#include "libc_private.h" +static int we_askshell(const char *, wordexp_t *, int); +static int we_check(const char *); + +/* + * wordexp -- + * Perform shell word expansion on `words' and place the resulting list + * of words in `we'. See wordexp(3). + * + * Specified by IEEE Std. 1003.1-2001. + */ +int +wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) +{ + int error; + + if (flags & WRDE_REUSE) + wordfree(we); + if ((flags & WRDE_APPEND) == 0) { + we->we_wordc = 0; + we->we_wordv = NULL; + we->we_strings = NULL; + we->we_nbytes = 0; + } + if ((error = we_check(words)) != 0) { + wordfree(we); + return (error); + } + if ((error = we_askshell(words, we, flags)) != 0) { + wordfree(we); + return (error); + } + return (0); +} + +static size_t +we_read_fully(int fd, char *buffer, size_t len) +{ + size_t done; + ssize_t nread; + + done = 0; + do { + nread = _read(fd, buffer + done, len - done); + if (nread == -1 && errno == EINTR) + continue; + if (nread <= 0) + break; + done += nread; + } while (done != len); + return done; +} + +static bool +we_write_fully(int fd, const char *buffer, size_t len) +{ + size_t done; + ssize_t nwritten; + + done = 0; + do { + nwritten = _write(fd, buffer + done, len - done); + if (nwritten == -1 && errno == EINTR) + continue; + if (nwritten <= 0) + return (false); + done += nwritten; + } while (done != len); + return (true); +} + +/* + * we_askshell -- + * Use the `freebsd_wordexp' /bin/sh builtin function to do most of the + * work in expanding the word string. This function is complicated by + * memory management. + */ +static int +we_askshell(const char *words, wordexp_t *we, int flags) +{ + int pdesw[2]; /* Pipe for writing words */ + int pdes[2]; /* Pipe for reading output */ + char wfdstr[sizeof(int) * 3 + 1]; + char buf[35]; /* Buffer for byte and word count */ + long nwords, nbytes; /* Number of words, bytes from child */ + long i; /* Handy integer */ + size_t sofs; /* Offset into we->we_strings */ + size_t vofs; /* Offset into we->we_wordv */ + pid_t pid; /* Process ID of child */ + pid_t wpid; /* waitpid return value */ + int status; /* Child exit status */ + int error; /* Our return value */ + int serrno; /* errno to return */ + char *np, *p; /* Handy pointers */ + char *nstrings; /* Temporary for realloc() */ + char **nwv; /* Temporary for realloc() */ + sigset_t newsigblock, oldsigblock; + const char *ifs; + + serrno = errno; + ifs = getenv("IFS"); + + if (pipe2(pdesw, O_CLOEXEC) < 0) + return (WRDE_NOSPACE); /* XXX */ + snprintf(wfdstr, sizeof(wfdstr), "%d", pdesw[0]); + if (pipe2(pdes, O_CLOEXEC) < 0) { + _close(pdesw[0]); + _close(pdesw[1]); + return (WRDE_NOSPACE); /* XXX */ + } + (void)sigemptyset(&newsigblock); + (void)sigaddset(&newsigblock, SIGCHLD); + (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); + if ((pid = fork()) < 0) { + serrno = errno; + _close(pdesw[0]); + _close(pdesw[1]); + _close(pdes[0]); + _close(pdes[1]); + (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + errno = serrno; + return (WRDE_NOSPACE); /* XXX */ + } + else if (pid == 0) { + /* + * We are the child; make /bin/sh expand `words'. + */ + (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + if ((pdes[1] != STDOUT_FILENO ? + _dup2(pdes[1], STDOUT_FILENO) : + _fcntl(pdes[1], F_SETFD, 0)) < 0) + _exit(1); + if (_fcntl(pdesw[0], F_SETFD, 0) < 0) + _exit(1); + execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u", + "-c", "IFS=$1;eval \"$2\";" + "freebsd_wordexp -f \"$3\" ${4:+\"$4\"}", + "", + ifs != NULL ? ifs : " \t\n", + flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null", + wfdstr, + flags & WRDE_NOCMD ? "-p" : "", + (char *)NULL); + _exit(1); + } + + /* + * We are the parent; write the words. + */ + _close(pdes[1]); + _close(pdesw[0]); + if (!we_write_fully(pdesw[1], words, strlen(words))) { + _close(pdesw[1]); + error = WRDE_SYNTAX; + goto cleanup; + } + _close(pdesw[1]); + /* + * Read the output of the shell wordexp function, + * which is a byte indicating that the words were parsed successfully, + * a 64-bit hexadecimal word count, a dummy byte, a 64-bit hexadecimal + * byte count (not including terminating null bytes), followed by the + * expanded words separated by nulls. + */ + switch (we_read_fully(pdes[0], buf, 34)) { + case 1: + error = buf[0] == 'C' ? WRDE_CMDSUB : WRDE_BADVAL; + serrno = errno; + goto cleanup; + case 34: + break; + default: + error = WRDE_SYNTAX; + serrno = errno; + goto cleanup; + } + buf[17] = '\0'; + nwords = strtol(buf + 1, NULL, 16); + buf[34] = '\0'; + nbytes = strtol(buf + 18, NULL, 16) + nwords; + + /* + * Allocate or reallocate (when flags & WRDE_APPEND) the word vector + * and string storage buffers for the expanded words we're about to + * read from the child. + */ + sofs = we->we_nbytes; + vofs = we->we_wordc; + if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND)) + vofs += we->we_offs; + we->we_wordc += nwords; + we->we_nbytes += nbytes; + if ((nwv = reallocarray(we->we_wordv, (we->we_wordc + 1 + + (flags & WRDE_DOOFFS ? we->we_offs : 0)), + sizeof(char *))) == NULL) { + error = WRDE_NOSPACE; + goto cleanup; + } + we->we_wordv = nwv; + if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) { + error = WRDE_NOSPACE; + goto cleanup; + } + for (i = 0; i < vofs; i++) + if (we->we_wordv[i] != NULL) + we->we_wordv[i] += nstrings - we->we_strings; + we->we_strings = nstrings; + + if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { + error = WRDE_NOSPACE; /* abort for unknown reason */ + serrno = errno; + goto cleanup; + } + + error = 0; +cleanup: + _close(pdes[0]); + do + wpid = _waitpid(pid, &status, 0); + while (wpid < 0 && errno == EINTR); + (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); + if (error != 0) { + errno = serrno; + return (error); + } + /* + * Check process exit status, but ignore ECHILD as the child may have + * been automatically reaped if the process had set SIG_IGN or + * SA_NOCLDWAIT for SIGCHLD, and our reason for waitpid was just to + * reap our own child on behalf of the calling process. + */ + if (wpid < 0 && errno != ECHILD) + return (WRDE_NOSPACE); /* abort for unknown reason */ + if (wpid >= 0 && (!WIFEXITED(status) || WEXITSTATUS(status) != 0)) + return (WRDE_NOSPACE); /* abort for unknown reason */ + + /* + * Break the null-terminated expanded word strings out into + * the vector. + */ + if (vofs == 0 && flags & WRDE_DOOFFS) + while (vofs < we->we_offs) + we->we_wordv[vofs++] = NULL; + p = we->we_strings + sofs; + while (nwords-- != 0) { + we->we_wordv[vofs++] = p; + if ((np = memchr(p, '\0', nbytes)) == NULL) + return (WRDE_NOSPACE); /* XXX */ + nbytes -= np - p + 1; + p = np + 1; + } + we->we_wordv[vofs] = NULL; + + return (0); +} + +/* + * we_check -- + * Check that the string contains none of the following unquoted + * special characters: <newline> |&;<>(){} + * This mainly serves for {} which are normally legal in sh. + * It deliberately does not attempt to model full sh syntax. + */ +static int +we_check(const char *words) +{ + char c; + /* Saw \ or $, possibly not special: */ + bool quote = false, dollar = false; + /* Saw ', ", ${, ` or $(, possibly not special: */ + bool have_sq = false, have_dq = false, have_par_begin = false; + bool have_cmd = false; + /* Definitely saw a ', ", ${, ` or $(, need a closing character: */ + bool need_sq = false, need_dq = false, need_par_end = false; + bool need_cmd_old = false, need_cmd_new = false; + + while ((c = *words++) != '\0') { + switch (c) { + case '\\': + quote = !quote; + continue; + case '$': + if (quote) + quote = false; + else + dollar = !dollar; + continue; + case '\'': + if (!quote && !have_sq && !have_dq) + need_sq = true; + else + need_sq = false; + have_sq = true; + break; + case '"': + if (!quote && !have_sq && !have_dq) + need_dq = true; + else + need_dq = false; + have_dq = true; + break; + case '`': + if (!quote && !have_sq && !have_cmd) + need_cmd_old = true; + else + need_cmd_old = false; + have_cmd = true; + break; + case '{': + if (!quote && !dollar && !have_sq && !have_dq && + !have_cmd) + return (WRDE_BADCHAR); + if (dollar) { + if (!quote && !have_sq) + need_par_end = true; + have_par_begin = true; + } + break; + case '}': + if (!quote && !have_sq && !have_dq && !have_par_begin && + !have_cmd) + return (WRDE_BADCHAR); + need_par_end = false; + break; + case '(': + if (!quote && !dollar && !have_sq && !have_dq && + !have_cmd) + return (WRDE_BADCHAR); + if (dollar) { + if (!quote && !have_sq) + need_cmd_new = true; + have_cmd = true; + } + break; + case ')': + if (!quote && !have_sq && !have_dq && !have_cmd) + return (WRDE_BADCHAR); + need_cmd_new = false; + break; + case '|': case '&': case ';': case '<': case '>': case '\n': + if (!quote && !have_sq && !have_dq && !have_cmd) + return (WRDE_BADCHAR); + break; + default: + break; + } + quote = dollar = false; + } + if (quote || dollar || need_sq || need_dq || need_par_end || + need_cmd_old || need_cmd_new) + return (WRDE_SYNTAX); + + return (0); +} + +/* + * wordfree -- + * Free the result of wordexp(). See wordexp(3). + * + * Specified by IEEE Std. 1003.1-2001. + */ +void +wordfree(wordexp_t *we) +{ + + if (we == NULL) + return; + free(we->we_wordv); + free(we->we_strings); + we->we_wordv = NULL; + we->we_strings = NULL; + we->we_nbytes = 0; + we->we_wordc = 0; +} |