diff options
| author | Klaatu <[email protected]> | 2015-05-17 15:33:21 +1200 |
|---|---|---|
| committer | Klaatu <[email protected]> | 2015-05-17 15:33:21 +1200 |
| commit | b0de699679e8f1e39af847ed172d1ba605b4370c (patch) | |
| tree | 01dac00471d61f727394e508c613b29cff0ceae5 | |
bulk upload of source
183 files changed, 9899 insertions, 0 deletions
diff --git a/00THANKS b/00THANKS new file mode 100644 index 0000000..9e33b28 --- /dev/null +++ b/00THANKS @@ -0,0 +1,6 @@ +D. J. Bernstein: daemontools author +Felix von Leitner: dietlibc, minit author +Jan Skakula: port to archlinux; making services +Pencho Marinov: always test the new versions +Ilian Kostadinov: many discusion obout ninit features +Boris Grozev: updates all manpages @@ -0,0 +1,129 @@ +0.14: 2010-01-19 00:27:01 + added nkillall.8 + gid is not default anymore. see ninitfeatures.h + uid supports 22:33:100:200:300 + nkillall: \e escape + shutdown: set cron off + nkillall: signals with letters like nsvc + shutdown and nkillall: makes more sync(2), flag -q + added THANKS ;-) + added helpers: remove procfs; thanks to them snvc is smaller + nsvc options -onumber -unumber; option -E + Cron has option -C + /etc/ninit/.nsvc_help + nsvc, shutdown, reload uses variables NINIT_MEMORY and NINIT_HOME + nsvc: option -S + shutdown: option -s + manpages for all programs in /sbin ;-) + update manpages (Boris Grozev) + Makefile: man_txt + serdo.c: read only one file again + better sleep in open_inout.h + serdo.c improvments; buildin: killall5, simple echo + nsvc.c: -C+number + scripts/conf + ninit.8: NONROOT USAGE, using /sbin/init with ninit + ninit-scan: (Wayne Marshall) + +0.13.7: 2009-12-16 10:47:50 + bootlog.c (flush_root) + 0.13.1.4 renamed to 0.13.2 + service start 'end' (if it exixts; X_OK) after finishing + fixed a bug in shutdown.c (thx to Jan) + With flag -s ninit-shutdown don't start halt and reboot services + shutdown.c: improvements; flags -S -q + shutdown.c: removed flags -s -q; new flags -E -v -T + added nkillall + shutdown.c: options -m and -E work together + nkillall print escape like echo + +0.13.1: 2009-06-27 12:59:38 + updated bootlog + Makefile logs 'make tests' in tests_log using boolog + fixing quotes in serdo + +0.13: 2009-01-10 18:11:42 + it's possible to set parameters in wait. example: some_service:180:3 + install-bin print help and string errors + better sync mode. maxsync is removed. echo 200 > sync + updated scripts/ninit_test.sh + comments (#) in depends, params, environ, wait, softlimit + install-bin (verbose mode) + nsvc -V + errmsg_put.c; buffer_*.c + setup, rsetup, sys-rsetup starts with args: $1=service $2=service_pid + EXTRACT_* trick (automatic create header files) + stuct process is 20 bytes on x86_64 (see struct_root.h) + changed BIFFER_INIT macro + utmp_io.c + Makefile: install_other + serdo is intslled only with: make install_other + t_write.h uses PIPE_BUF (thx Laurent Bercot) + nsvc.8 improvements + ninit_test.sh creates services in ./etc/ninit/ + ninit-huge + added printf.c and ninit.spec + make FLAG_DEBUG=no + removed flag X_OK in some syscalls access. + better addprocess + +0.12.1: 2008-01-03 17:15:08 + ninit-depends. convert directory to file (depends.dir -> depends) + removed unused stat.h in headers + updated serdo (static) + two environ vars: NINIT_HOME, INIT_HOME. (Thanks to Stamatis Mitrofanis) + ninit logo: /etc/ninit/.sync + install-bin uses chown32 instead chown on some systems + err.c and err_b.c uses the macros va_start and va_arg + fu.c (u &= 0xffffffff) + +0.12: + almost all arrays are moved in stack. small data and bss sections. + assembler functions (i386) for some DJB functions. + modifications in Makefile. + 100 Euro security guarantee. + +0.11.2: + ninit-reload accept agument -e (change environ) -E file_env + program ~/sys/update + service flags: pause, pause-wait + service flag cron: a:b[:c] + can contain many lines. + flag -K for nsvc. + pidfilehack --> ninit-pidfile. + make i386 -- build static daemons (don't use dietlibc) + Makefile is smaller and simpler + gcc-4.1.2 works now. + install-bin + stuct mem in initialized in the main program. + +0.11.1: + ninit-reload accepts args (-r3 -r5 -r33 ...) + ninit-inittab sets the variables NINIT_RUNLEVEL, INIT_VERSION + if /etc/minit/{in|out} FIFO's exist then make symbolic links. + new run flags: sys-rsetup, pidfile + if the service sysvinit exist, ninit create /dev/initctl + ninit-reload and nsvc checks for environ NINIT_HOME + nsvc -[drR] ALL - change all services. + Change service ALL with: nsvc -[drR] ops ALL + new program: ninit-sysvinit. configuration file: sysvinit-timeout + fimeout[:fork-mode]. example: echo 600:0 > sysvinit-timeout + ninit catch signal SIGPWR + new run flags: alarm, maxsync + nsvc output is different + shell script ninit-service + new program run-wait + +0.11: + Sun Jun 17 22:08:22 EEST 2007 + I decided to rename all without changes. + The name ninit must be spelled nano-init. + +0.9.11: + rewritten by Nikola Vladov + +0.9.1: + fix embarassing typo in msvc (Gelu G. Lupas) + +0.9: + See minit CHANGES - http://www.fefe.de/minit @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c0e4ea4 --- /dev/null +++ b/Makefile @@ -0,0 +1,221 @@ +SHELL = /bin/sh +VPATH = contrib:djb:lib:misc +DESTDIR:=/ + +DIET= +CC=gcc $(GCC_FLAGS) +CFLAGS=-pipe -Os -Wall -W +LDFLAGS=-s +FLAG_DEBUG = no + +MYARCH:=$(shell uname -m | sed -e 's/i[4-9]86/i386/' -e 's/armv[3-6]t\?e\?[lb]/arm/') +MAN_PAGES:=$(shell test -d /usr/share/man && echo usr/share/man || echo usr/man) + +ifeq ($(MYARCH),i386) +include system/$(MYARCH)/Flags +endif +ifeq ($(MYARCH),x86_64) +include system/$(MYARCH)/Flags +endif + +# If the assembler fail on your host change i386 bellow to XXXX +ifeq ($(MYARCH),i386) +ALL_LIB = $(shell sed -e 's/Z./S/' -e 's/^[a-z]*\///' library_files) +else +ALL_LIB = $(shell sed -e 's/Z.//' -e 's/^[a-z]*\///' library_files) +endif + +ifdef DIET +CFLAGS += -nostdinc +else +CFLAGS += $(OPTIMIZATION) +endif + +N_FLAGS = -nostdlib -DINIT_SYSTEM system/$(MYARCH)/start.o +N_FLAGS += $(CFLAGS) $(LDFLAGS) +N_LIB = ninit.a system/$(MYARCH)/system.a + +ifeq ($(FLAG_DEBUG),no) +CCC_ = @echo ' CC $< ' ; +CCL_ = @echo ' CL $< -> $@ ' ; +C = @ +else +CCC_ = +CCL_ = +C = +endif + +CC_C = $(DIET) $(CC) $(CFLAGS) +CC_L = $(DIET) $(CC) $(CFLAGS) $(LDFLAGS) + +CCC = $(CCC_) $(CC_C) +CCL = $(CCL_) $(CC_L) +STR = strip -R .comment -R .note + +ALL = ninit run wait update nsvc reload pidfile reboot \ + runlevel sysvinit inittab shutdown pututmpid bootlog install-bin \ + env sleeprun conditional-init serdo argv0 ninit-mmap ninit-huge nkillall \ + remove procfs +ALL_MAN = ninit.8.gz nsvc.8.gz pututmpid.8.gz shutdown.8.gz nkillall.8.gz \ + runlevel.8.gz sysvinit.8.gz pidfile.8.gz reboot.8.gz reload.8.gz \ + bootlog.8.gz service.8.gz inittab.8.gz scan.8.gz + +BYTE_C = $(wildcard djb/byte_*.c) +BUFFER_C = $(wildcard djb/buffer_*.c lib/err_b.c) + +all: $(ALL) $(ALL_MAN) Version start_tests +ninit.a: $(ALL_LIB) + ar cr $*.a $^ + +include_h_files = all_defs.h buffer_defs.h byte_defs.h utmp_defs.h \ + addprocess.h open_inout.h tryservice_nsvc.h \ + findservice.h mmap_alloca.h sighandler.h wait_services.h get_services.h \ + ninit.h t_write.h initreq.h ninitfeatures.h tryservice.h error_table.h \ + struct_root.h uid.h +help_files = $(include_h_files) int_defs.h pagesize_defs.h process_defs.h \ +ninit.a + +%.o: %.c $(include_h_files) process_defs.h + $(CCC) -c -o $@ $< +S%.o: S/%.S $(include_h_files) + $(CCC) -c -o $@ $< + +printf: printf.c + $(CCL) -o $@ $< + $(C) $(STR) $@ +bin-$(MYARCH)/%: %.c $(help_files) + $(CCL_) $(CC) $(N_FLAGS) $(TINY_FLAGS) -o $@ $< $(N_LIB) +%: %.c $(help_files) + $(CCL) -o $@ $< ninit.a + +ninit-mmap.c: ninit.c printf + $(C) ./printf '%s\n%s\n' '#define INIT_MMAP' '#include "ninit.c"' > $@ +ninit-huge.c: ninit.c printf + $(C) ./printf '%s\n%s\n' '#define INIT_TIMEOUT_WRITE' '#include "ninit.c"' > $@ +buffer_defs.h: $(BUFFER_C) + $(C) ./get_headers $@ $^ > $@ +byte_defs.h: $(BYTE_C) djb/str_len.c + $(C) ./get_headers $@ $^ > $@ +utmp_defs.h: lib/do_wtmp.c lib/utmp_io.c + $(C) ./get_headers $@ $^ > $@ +all_defs.h: library_files printf + $(C) ./get_headers $@ -Lint_defs.h `sed -e 's/\.o/\.c/' -e 's/Z/djb/' library_files` | sed -e '/struct.*utmp/d' -e '/buffer/d' > $@ + $(C) ./printf '\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n\n' \ + "ARCH = $(MYARCH)" "`uname -a || true`" "DIET = $(DIET)" "CC = $(CC)" \ + "CFLAGS = $(CFLAGS)" "LDFLAGS = $(LDFLAGS)" "FLAG_DEBUG = $(FLAG_DEBUG)" \ + +process_defs.h: misc/tryprocess.c all_defs.h + $(C) rm -f $@Z; $(CC_L) -o $@Z $< + ./$@Z > $@ + $(C) sed -ne /_MASK_LEN/p -e /_SIZE/p -e /_NAME_/p -e /_CODED/p $@ + $(C) rm -f $@Z +int_defs.h: misc/tryulong32.c misc/try_int.h2 + $(C) ( ( rm -f $@Z; $(CC_L) -o $@Z $< && ./$@Z ) >/dev/null 2>&1 \ + && sed -e 's/Z/long/' misc/try_int.h2 || \ + sed -e 's/Z/int/' misc/try_int.h2 ) > $@ + $(C) sed -n -e '/typedef/p' $@; rm -f $@Z +pagesize_defs.h: misc/trypagesize.c + $(C) ( ( rm -f $@Z; $(CC_L) -o $@Z $< && ./$@Z ) >/dev/null 2>&1 \ + && echo '#define page_size 4096' || echo '#define page_size 8192' ) > $@ + $(C) cat $@; rm -f $@Z +initreq: misc/initreq.c + $(CCL) -o $@ $< + +withdiet: + make DIET='diet -Os' +nodiet: + make DIET= + +B=bin-$(MYARCH) +STATIC_FILES=$(shell echo '' $(ALL) | sed -e "s/ */ $(B)\//g") +$(MYARCH): + test -d bin-$(MYARCH) || mkdir bin-$(MYARCH) + make DIET= + cd system/$(MYARCH) && make FLAG_DEBUG=$(FLAG_DEBUG) + make system-$(MYARCH) DIET= LDFLAGS="$(TINY_LDFLAGS) $(LDFLAGS)" +$(MYARCH)-tiny: printf + $(C) ./printf "\n%s\n\t%s\n\n" \ + 'exec the following line:' \ + 'make clean $(MYARCH) TINY_LDFLAGS=-Wl,-N' +system-$(MYARCH): $(STATIC_FILES) printf + $(C) ./printf "\n\t%s\n\t%s\n\n" \ + 'You can install ./'$(B)'/* static-files with:' \ + 'cp ./'$(B)'/* . ; make install' + +clean: + rm -f $(ALL) \ + system/$(MYARCH)/*.o system/$(MYARCH)/*.a system/$(MYARCH)/system_*.S \ + *.o *.a a.out contrib/*.o djb/*.o djb/*.s S/*.o misc/*.o misc/*.s \ + lib/*.o lib/*.s *.8.gz *_defs.h *_defs.hZ x y z initreq printf \ + ninit_server.sh services.sh after-reload ninit.data \ + ninit-mmap.c ninit-huge.c Version tests_log* OTHER + rm -rf home etc bin-* mantxt + +dietlibc/bin-$(MYARCH)/diet: + cvs -d :pserver:[email protected]:/cvs -z9 co dietlibc + cd dietlibc && make +dietbuild: dietlibc/bin-$(MYARCH)/diet + DIETHOME=$(CURDIR)/dietlibc make DIET="$(CURDIR)/$< -Os" +%.gz: man/% + $(C) gzip -9c $< > $@ +mantxt/%: man/%.8 + $(C) test -d mantxt || mkdir mantxt + man ./$< | col -b > [email protected] +man_txt: $(patsubst %.8.gz,mantxt/%,$(ALL_MAN)) + +tests: scripts/tests.sh $(ALL) Version + ./bootlog -ctr 200000 tests_log ./$< + @sleep 1; ./printf 'Above output is saved in file: \e[1;34mtests_log\e[0;39m.\r\nRead it using the programs cat/more/less.\r\n' +strip: $(patsubst printf,,$(ALL)) + $(STR) $^ bin-$(MYARCH)/* || true + +D=$(DESTDIR) +install: $(ALL) $(ALL_MAN) scripts/update.sh Version printf + ./install-bin $(D) < misc/BIN + ./install-bin $(D)/$(MAN_PAGES) < misc/MAN + ./scripts/update.sh $(D) + $(C) ./printf "\n\t%s\n\n" \ + 'Install some additional programs with: make install_other' + +install_other: $(ALL) + sed -e 's/# //' -e /600/q misc/BIN > OTHER + ./install-bin $(D) < OTHER + +start_tests: $(ALL) $(ALL_MAN) Version printf + $(C) ./printf "\n\tStart now: make tests\n\n" +ser_vi_ces: inittab + ./inittab /etc/inittab /etc/ninit services.sh + ./services.sh +package: distro +distro: + umask 022 && mkdir -p /tmp/ninit.distro/$(MAN_PAGES) + make install DESTDIR=/tmp/ninit.distro + cd /tmp/ninit.distro && tar -cjf \ + /tmp/$(VERSION)-$(MYARCH).tar.bz2 --owner=root --group=root * + +VERSION=ninit-$(shell head -n 1 CHANGES|sed 's/:.*//') +VERSION_LONG=$(shell head -n 1 CHANGES) +TIMENOW=$(shell date -u "+%Y-%m-%d %H:%M:%S") +CURNAME=$(notdir $(CURDIR)) +RRR=--owner=root --group=root +Version: CHANGES printf + ./printf '\r\n\e[1;34m%s\e[0;39m:%s\r\n%s\e[1;35m%s\e[0;39m\r\n' \ + 'NINIT' ' Version: $(VERSION_LONG)' \ + 'source: ' 'http://riemann.fmi.uni-sofia.bg/ninit/' > Version + +tests.tar: + tar -cv $(RRR) home/default/* home/env/environ home/env/run \ + home/sh/* home/S/* home/sleep/* | gzip -9 > home.tar.gz +rename: + if test $(CURNAME) != $(VERSION); then cd .. && mv $(CURNAME) $(VERSION); fi +TAR=tar +TAR_OPT= +tar: rename + sed -e "1s/^\(.*: \)\(.*\)/\1$(TIMENOW)/" CHANGES > CHANGES.tmp + mv CHANGES.tmp CHANGES + cd .. && $(TAR) cvjf $(VERSION).tar.bz2 $(TAR_OPT) $(RRR) \ + --exclude $(VERSION)/dietlibc $(VERSION) +packit: + make clean tar TAR=tar.f TAR_OPT=--sort +rpm: ninit.spec + rpmbuild -ba --clean $< @@ -0,0 +1,213 @@ +See also: http://riemann.fmi.uni-sofia.bg/ninit/ + +Each service gets its own directory under /etc/ninit (change this in the +source, it's a #define right at the start of ninitfeatures.h). + + +Each service directory can contain the following files/symlinks: + + depends + + a plain text file containing a service name per line. + Example: /etc/ninit/sshd/depends could contain "network". + Each of these services will be started before this service is + started. If you need to wait for static initializations to + complete, use the sync flag. See also the wait flag below. + + run + + a symbolic link to the program name. No hard link, because argv[0] + for the programs is created by extracting the part after the last + slash in the contents of the symbolic link. + Example: "/usr/bin/sshd" would be run with argv[0]="sshd". + + end + + similar to run. After the service finish "end" will be executed. + The helper does not set environ, softlimit, uid/gid restrictions. + You can put there for example: + #!/bin/sh + exec /bin/nsvc -o service_name + Use this option instead of sync or wait mode. Let for example + services B,C,D must be started after A finish. There are two + possible solutions: + Bad: start A in sync mode + Good: start A i normal mode and put in "end" + #!/bin/sh + exec /bin/nsvc -o B C D + + params + + a plain text file containing command line parameters for the + service, one parameter per line. No shell expansion is done. If + you need shell expansion, have run point to a shell script instead + of the real daemon. Note: Have the shell script exec the daemon + instead of simply running it to save system resources. + + environ + + similar to params. run appends contents of this file to the environ. + If the first line has zero length, unset all environ. + If a line does not have '=' (HOME), unset this variable. + + wait + + similar to params. /etc/inint/run waits for services included in + this file to finish and after that start a current service. + Include wait services also in depends. This is different from sync. + Let a service B must be started after a service A finish. + One can sync A. This will block all other services. + In this case it's better to use wait instead of sync. + It's possible to set wait parameters (see maxwait) at the end of + each entry. Example: some_service:180:3 + + maxwait + + a plain text file containing the values n1:n2. Wait no more + than n1 sec a service for finish. See wait. Default is 600 sec. + The value n1=0 means -- wait until the service finish. + + + softlimit + + see DJB program softlimit. Similar to params. Lines + with the same options as softlimit (skip leading '-'). Example: + echo m300000 > softlimit; echo o30 >> softlimit + + respawn + + touch this file to make ninit respawn the process when it dies. + This should be touched for getty and network servers. + + sync + + touch this file to make ninit wait until the service ends. sync is + mutually exclusive with respawn. This is meant for static + initializations like "ifconfig". See also wait. + If sync contains a nonzero number n ninit will wait max n sec + the service to finish. If it does not ends until n secs then + ninit continues to work. Example: echo 600 > sync + + log + + if this directory exists, it is taken as service and ninit creates + a named pipe log/in and soft link of log/in to out. If the log + service can not be started, this service will block if it writes + to stdout. + + nice + + a plain text file containing the value to add to the nice level + via the nice system call. + + sleep + + a plain text file containing the value n. sleep n secs after fork + before running child. + + in + + this file(named pipe) is used for stdin. + + out + + this file(named pipe) is used for stdout and stderr. + e.g. a symlink to /dev/null + + gid + + a plain text file containing a number. + Exec the program with this GID. Example echo -n 234 > gid + To activate this feature edit the file ninitfeatures.h + and install the package again. + + uid + + exec the program with this UID. It can contain also UID:GID + It is possible to write here also the supplementary groups. + For example echo 23:99:240:320:100 > uid start the service with: + UID=23, GID=99, GROUPS=99,240,320,100. + + setup + + if this file exist it is started just before run in sync mode. + If uid/gid or softlimit exist they are applied first and + after that setup is executed. + + rsetup + + similar to setup. It is executed before setup as root and + not softlimit, uid/gid, in/out restrictions. If you + want to create/modify params, wait, depends... see sys-rsetup flag. + + sys-rsetup + + similar to setup. It is executed first as root. + It can be used to create/modify params, wait, depends... + + pidfile + + easy method to setup services which run in background. + Prepare them as ordinary services and write the name of the pidfile. + Don't use link here! + Example: echo -n /var/run/gpm.pid > pidfile + + alarm + + a plain text file containing a number n. + Do alarm(n) before starting the child. + + pause + + if this file exist run selfkills with SIGSTOP signal. + + pause-wait + + if this file exist run-wait selfkills with SIGSTOP signal. + + cron + + a plain text file containing lines with numbers a:b[:c] + for each line run wait find a solution of + cron = 60 * (a*x+b) > now (x is integer) + The smallest cron is next cron-start for this service. + The number a=10080 (24*60*7) is special. For example 10080:25 + means: Sunday 00:25:00 UTC + +ninit will try to run the command line arguments as services. The +kernel passes its arguments to init. That means you can for example +have a service /etc/ninit/sos-shell that starts a /bin/sh and then use +LILO to boot "bzImage sos-shell". ninit will then run that service. +If none of the services worked (or none were given), ninit will spawn +the service "default". The normal way to configure ninit is to have +default be an empty service and just list all the services you want +ninit to start at boot time in default/depends. + +Other special services (besides "default") are "ctrlaltdel" and "kbreq". +ctrlaltdel will be run when the console user presses ctrl-alt-del and is +meant to reboot the computer. kbreq is the keyboard request, which +can be mapped using loadkeys. On my box, it is on Alt+Arrow-Up. I use +it to shut down the computer. + +-------------------------- +Memory allocation in NINIT. ninit uses only alloca for RAM. + +One service = 21 + strlen(service_name). Example getty/1 is 28 bytes. +If you need to load more than 50 services then use at boot process +something like: + /sbin/ninit -M3200 + +after reload/reboot ninit will work with 3200 bytes buffer. +default buffer is 1536. Good for 50-60 services. +If someone uses more than 50 services let me know. + +-------------------------- +After building a new ninit test/install it with: + ninit-reload -v -u /path/to/new/ninit [-M2000] + cp /path/to/new/ninit /sbin/ninit + ninit-reload -v -u /sbin/ninit [argv1 argv2 ...] +some of argvs can be -M2000 or -M3200 ... + +There is no need of reboot! Dump memory buffer with: + ninit-reload -m > /tmp/ninit.mem + less /tmp/ninit.mem diff --git a/S/atoulong.S b/S/atoulong.S new file mode 100644 index 0000000..7d141ed --- /dev/null +++ b/S/atoulong.S @@ -0,0 +1,17 @@ +.globl atoulong +.type atoulong,@function +atoulong: + xorl %edx,%edx + xorl %eax,%eax + movl 4(%esp),%ecx + jmp .L1 +.L2: + imull $10,%eax,%eax + addl %edx,%eax + incl %ecx +.L1: + movb (%ecx),%dl + subb $48,%dl + cmpb $9,%dl + jbe .L2 + ret diff --git a/S/byte_copy.S b/S/byte_copy.S new file mode 100644 index 0000000..44ff449 --- /dev/null +++ b/S/byte_copy.S @@ -0,0 +1,23 @@ +.globl byte_copy +.type byte_copy, @function +byte_copy: + pushl %edi + pushl %esi + movl 12(%esp), %edi + movl 16(%esp), %ecx + movl 20(%esp), %esi + cld + +#ifdef BYTE_COPY_FAST + movl %ecx, %eax + shrl $2, %ecx + andl $3, %eax + + rep movsl + movl %eax, %ecx +#endif + rep movsb + + popl %esi + popl %edi + ret diff --git a/S/byte_copyr.S b/S/byte_copyr.S new file mode 100644 index 0000000..bcc9b21 --- /dev/null +++ b/S/byte_copyr.S @@ -0,0 +1,22 @@ +.text +.globl byte_copyr +.type byte_copyr, @function +byte_copyr: + pushl %edi + pushl %esi + movl 12(%esp), %edi + movl 20(%esp), %esi + movl 16(%esp), %ecx + + decl %edi + decl %esi + addl %ecx, %edi + addl %ecx, %esi + + std + rep movsb + cld + + popl %esi + popl %edi + ret diff --git a/S/byte_diff.S b/S/byte_diff.S new file mode 100644 index 0000000..f9d6c16 --- /dev/null +++ b/S/byte_diff.S @@ -0,0 +1,19 @@ +.global byte_diff +.type byte_diff,function +byte_diff: + pushl %esi + pushl %edi + xorl %eax, %eax + movl 12(%esp), %esi + movl 16(%esp), %ecx + movl 20(%esp), %edi + + cld + rep cmpsb + jz .Lout + sbbl %eax, %eax + orl $1, %eax +.Lout: + popl %edi + popl %esi + ret diff --git a/S/byte_set.S b/S/byte_set.S new file mode 100644 index 0000000..a61b3ad --- /dev/null +++ b/S/byte_set.S @@ -0,0 +1,5 @@ +.globl byte_set +.type byte_set, @function +byte_set: + movb 12(%esp), %al + jmp byte_zero_end diff --git a/S/byte_zero.S b/S/byte_zero.S new file mode 100644 index 0000000..01c166b --- /dev/null +++ b/S/byte_zero.S @@ -0,0 +1,16 @@ +.globl byte_zero +.type byte_zero, @function +byte_zero: + xorb %al, %al + +.globl byte_zero_end +byte_zero_end: + pushl %edi + movl 8(%esp), %edi + movl 12(%esp), %ecx + + cld + rep stosb + + popl %edi + ret diff --git a/S/str_chr.S b/S/str_chr.S new file mode 100644 index 0000000..5fec8b2 --- /dev/null +++ b/S/str_chr.S @@ -0,0 +1,17 @@ +.globl str_chr +.type str_chr, @function +str_chr: + pushl %esi + movl 8(%esp), %esi + movb 12(%esp), %ah +.L1: + lodsb + cmpb %ah,%al + je .L2 + testb %al,%al + jne .L1 +.L2: + leal -1(%esi), %eax + subl 8(%esp), %eax + popl %esi + ret diff --git a/S/str_copy.S b/S/str_copy.S new file mode 100644 index 0000000..c24dbac --- /dev/null +++ b/S/str_copy.S @@ -0,0 +1,18 @@ +.globl str_copy +.type str_copy, @function +str_copy: + pushl %edi + pushl %esi + movl 12(%esp), %edi + movl 16(%esp), %esi +.L1: + lodsb + stosb + testb %al,%al + jne .L1 + + leal -1(%edi), %eax + subl 12(%esp), %eax + popl %esi + popl %edi + ret diff --git a/S/str_copyn.S b/S/str_copyn.S new file mode 100644 index 0000000..7a8765c --- /dev/null +++ b/S/str_copyn.S @@ -0,0 +1,22 @@ +.globl str_copyn +.type str_copyn, @function +str_copyn: + pushl %edi + pushl %esi + movl 12(%esp), %edi + movl 16(%esp), %esi + movl 20(%esp), %ecx +.L1: + decl %ecx + js .L2 + lodsb + stosb + testb %al,%al + jne .L1 + decl %edi +.L2: + movl %edi, %eax + subl 12(%esp), %eax + popl %esi + popl %edi + ret diff --git a/S/str_diff.S b/S/str_diff.S new file mode 100644 index 0000000..a90724e --- /dev/null +++ b/S/str_diff.S @@ -0,0 +1,22 @@ +.globl str_diff +.type str_diff, @function +str_diff: + pushl %edi + pushl %esi + movl 12(%esp), %esi + movl 16(%esp), %edi +.L1: + lodsb + scasb + jne .L2 + testb %al,%al + jne .L1 + xorl %eax,%eax + jmp .L3 +.L2: + sbbl %eax,%eax + orb $1,%al +.L3: + popl %esi + popl %edi + ret diff --git a/S/str_diffn.S b/S/str_diffn.S new file mode 100644 index 0000000..954d88f --- /dev/null +++ b/S/str_diffn.S @@ -0,0 +1,26 @@ +.globl str_diffn +.type str_diffn, @function +str_diffn: + pushl %edi + pushl %esi + movl 12(%esp), %esi + movl 16(%esp), %edi + movl 20(%esp), %ecx +.L1: + decl %ecx + js .L2 + lodsb + scasb + jne .L3 + testb %al,%al + jne .L1 +.L2: + xorl %eax,%eax + jmp .L4 +.L3: + sbbl %eax,%eax + orb $1,%al +.L4: + popl %esi + popl %edi + ret diff --git a/S/str_len.S b/S/str_len.S new file mode 100644 index 0000000..ba3fa7e --- /dev/null +++ b/S/str_len.S @@ -0,0 +1,11 @@ +.globl str_len +.type str_len, @function +str_len: + movl 4(%esp), %ecx + orl $-1, %eax +.L1: + incl %eax + cmpb $0, (%ecx, %eax) + jne .L1 + + ret diff --git a/S/str_rchr.S b/S/str_rchr.S new file mode 100644 index 0000000..032c393 --- /dev/null +++ b/S/str_rchr.S @@ -0,0 +1,24 @@ +.globl str_rchr +.type str_rchr, @function +str_rchr: + pushl %esi + movl 8(%esp), %esi + movb 12(%esp), %ah + xorl %ecx, %ecx +.L1: + lodsb + cmpb %ah,%al + jne .L0 + movl %esi, %ecx +.L0: + testb %al,%al + jne .L1 + + testl %ecx, %ecx + jnz .L3 + movl %esi, %ecx +.L3: + subl 8(%esp), %ecx + leal -1(%ecx), %eax + popl %esi + ret diff --git a/addprocess.h b/addprocess.h new file mode 100644 index 0000000..e4c04cb --- /dev/null +++ b/addprocess.h @@ -0,0 +1,30 @@ +/* 0 <= mem.l <= mem.r <= mem.a */ + +/* add process to data structure, return index or -1 */ +static int addprocess(void *p, char *service) { + unsigned int root_len, serv_len = str_len(service) + 1; + void *name; + struct process *pr; + + root_len = mem.l + PROCESS_SIZE; + if (root_len + serv_len + 32 > mem.r) + { write(1,"init: out of memory\n",20); return -1; } + + mem.r -= serv_len; + ++maxprocess; + + pr = root; + root = mem.x + (mem.r & ~15) - root_len; + byte_copy(root, mem.l, pr); + + pr = root + maxprocess; + byte_copy(pr, PROCESS_SIZE, p); + + mem.l += PROCESS_SIZE; + name = mem.x + mem.r; + byte_copy(name, serv_len, service); + + pr->name = process_name_set; + next_cron = 0; + return maxprocess; +} diff --git a/check_opt.h b/check_opt.h new file mode 100644 index 0000000..610edd8 --- /dev/null +++ b/check_opt.h @@ -0,0 +1,8 @@ +static int check_opt(char **argv, char **opt) { + if (argv[0][2]) { *opt = argv[0]+2; return 0; } + else if (argv[1]) { *opt = argv[1]; return 1; } + carp("Option ",argv[0]," requires an argument"); + _exit(1); +} + +#define chk_opt(argv,opt) argv+=check_opt(argv,&opt) diff --git a/contrib/argv0.c b/contrib/argv0.c new file mode 100644 index 0000000..e2eeb81 --- /dev/null +++ b/contrib/argv0.c @@ -0,0 +1,13 @@ +#include "../ninitfeatures.h" +#include "../error_table.h" + +int main(int argc,char **argv,char **envp) { + errmsg_iam("argv0"); + if (argc < 3) { + carp("usage: argv0", " realname program [ arg ... ]"); + return 100; + } + pathexec_run(argv[1],argv + 2,envp); + carp("unable to run ",argv[1],": ",error_string(table,errno)); + return 111; +} diff --git a/contrib/bootlog.c b/contrib/bootlog.c new file mode 120000 index 0000000..f2f9083 --- /dev/null +++ b/contrib/bootlog.c @@ -0,0 +1 @@ +bootlog_sbrk.c
\ No newline at end of file diff --git a/contrib/bootlog.h b/contrib/bootlog.h new file mode 100644 index 0000000..967ed6d --- /dev/null +++ b/contrib/bootlog.h @@ -0,0 +1,100 @@ +/* return -1 on error */ +static int xx_write(int fd, void *buf, size_t len) { + char *x = buf; + ssize_t w; + while (len) { + w = write(fd, buf, len); + if (w <= 0) { + if (w < 0 && errno == EINTR) continue; + return -1; + } + x += w; + len -= w; + } + return 0; +} + +/* return 0 if closed or error, -1 temporary error */ +static int do_io(void *buf, int len) { + int r = read(0,buf,len); + if (r<0) + if (errno != EINTR) r = 0; + if (r>0) xx_write(1,buf,r); + return r; +} + +static int mk_backup() { + if (flag_rename) { + if (rename(name, flag_rename) && errno != ENOENT) return -1; + flag_rename = 0; + } + return 0; +} + +static void write2(char *s) { write(2,s,str_len(s)); } + +int main(int argc, char **argv) { + unsigned long len=0; + int pid, pi[2]; + + for (;;) { + char *p; + argc--; + argv++; + if ((p=argv[0]) == 0 || *p != '-') break; + while (*++p) + switch (*p) { + case 'a': m |= O_APPEND; break; + case 't': m |= O_TRUNC; break; + case 'c': m |= O_CREAT; break; + case 'r': ++flag_rename; break; + case '2': ++flagstderr; break; + case '1': ++flagstdout; break; + default: + goto usage; + } + } + + if (argc<3) { + usage: + write2("usage: bootlog [-12ctar] size logfile program args...\n"); + _exit(1); + } + if (scan_ulong(argv[0], &len) == 0) goto usage; + if ((flagstderr | flagstdout) == 0) { + ++flagstdout; + ++flagstderr; + } + name=argv[1]; + + for (pid=0; pid<3; pid++) + if (fcntl(pid,F_GETFL,0) == -1) goto do_it; + + if (pipe(pi)) goto do_it; + while ((pid=fork()) < 0); + + if (pid==0) { + close(pi[1]); + while ((pid=fork()) < 0); + if (pid==0) { + dup2(pi[0],0); + close(pi[0]); + loop(len); + } + _exit(0); + } else { + close(pi[0]); + waitpid(pid, 0, 0); + if (flagstdout) { dup2(pi[1],1); } + if (flagstderr) { dup2(pi[1],2); } + close(pi[1]); + } + + do_it: + argv += 2; + pathexec_run(argv[0], argv, environ); + write2("bootlog: "); + write2(argv[0]); + write2(": exec error\n"); + _exit(127); +} diff --git a/contrib/bootlog_mmap.c b/contrib/bootlog_mmap.c new file mode 100644 index 0000000..7bd9583 --- /dev/null +++ b/contrib/bootlog_mmap.c @@ -0,0 +1,96 @@ +/* bootlog.c */ +/* diet -Os gcc -o bootlog bootlog.c -Wall -W */ + +#include <unistd.h> +#include <alloca.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> /* rename */ +#include <sys/mman.h> +#include <sys/wait.h> +#include "../ninitfeatures.h" + +static int xx_write(int fd, void *buf, size_t len); +static int do_io(void *buf, int len); +static int mk_backup(); + +struct mem { + struct mem *x; + unsigned int p; +}; + +static struct mem *last, *root; +static char *flag_rename, *name; +static int flagstderr, flagstdout, m; +int fd = -1; + +#include "../pagesize_defs.h" +#define mem_size sizeof(struct mem) +#define alloc_size (page_size - mem_size) + +void *mmap_alloc() { + struct mem *m; + m=mmap(0,page_size,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0); + if (m==(struct mem*)-1) return 0; + /* kernel must zeroed m->p and m->x */ + + if (last) last->x = m; + else root = m; + last = m; + return ((void *)m) + mem_size; +} + +static void flush_root() { + if (mk_backup()) return; + if (fd < 0) fd = open(name, O_WRONLY | m, 0644); + if (fd < 0) return; + while (root) { + void *x = root->x; + xx_write(fd, ((void *)root) + mem_size, root->p); + root->p = 0; + if (root == last) break; + munmap(root, page_size); + root = x; + } +} + +static void loop(unsigned long len) { + char *buf = 0; + int r; + if (flag_rename) { + char *d, *s = name; + d = flag_rename = alloca(str_len(name) + 5); + while (*s) *d++ = *s++; + d[0] = '~'; + d[1] = 0; + } + while (len) { + if (buf == 0 && (buf=mmap_alloc()) == 0) break; + + if (last->p >= alloc_size) { + flush_root(); + if (last->p) { buf = 0; continue; } + } + + r = do_io(buf + last->p, alloc_size - last->p); + if (r==0) break; + if (r<0) continue; + + if ((unsigned long)r > len) r = len; + last->p += r; + len -= r; + } + + if (buf==0 || len==0) { + char tmp[1024]; + while (do_io(tmp,sizeof(tmp))); + } + + mk_backup(); + flag_rename = 0; + flush_root(); + fsync(fd); + close(fd); +} + +#include "bootlog.h" diff --git a/contrib/bootlog_sbrk.c b/contrib/bootlog_sbrk.c new file mode 100644 index 0000000..525fcdc --- /dev/null +++ b/contrib/bootlog_sbrk.c @@ -0,0 +1,73 @@ +/* bootlog.c */ +/* diet -Os gcc -o bootlog bootlog.c -Wall -W */ + +#include <unistd.h> +#include <alloca.h> +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> /* rename */ +#include <sys/wait.h> +#include "../ninitfeatures.h" +#define BRKINCR 1024 + +static int xx_write(int fd, void *buf, size_t len); +static int do_io(void *buf, int len); +static int mk_backup(); + +static char *root, *last, *end; +static char *flag_rename, *name; +static int flagstderr, flagstdout, m; +int fd = -1; + +static void *setbrk(ssize_t incr) { + void *x = sbrk(incr); + if ((void *)-1 == x) return x; + if (root == 0) root = last = x; + end = x + incr; + return 0; +} + +static void flush_root() { + if (mk_backup()) return; + if (fd < 0) fd = open(name, O_WRONLY | m, 0644); + if (fd < 0 || root==0) return; + xx_write(fd, root, last-root); + last = root; + setbrk((ssize_t)BRKINCR - (end-root)); +} + +static void loop(unsigned long len) { + int r; + if (flag_rename) { + char *d, *s = name; + d = flag_rename = alloca(str_len(name) + 5); + while (*s) *d++ = *s++; + d[0] = '~'; + d[1] = 0; + } + while (len) { + if (last >= end) flush_root(); + if (last >= end && setbrk(BRKINCR)) break; + + r = do_io(last, end - last); + if (r==0) break; + if (r<0) continue; + + if ((unsigned long)r > len) r = len; + last += r; + len -= r; + } + + if (last >= end || len==0) { + char tmp[1024]; + while (do_io(tmp,sizeof(tmp))); + } + + mk_backup(); + flag_rename = 0; + flush_root(); + fsync(fd); + close(fd); +} + +#include "bootlog.h" diff --git a/contrib/conditional-init.c b/contrib/conditional-init.c new file mode 100644 index 0000000..10c69cc --- /dev/null +++ b/contrib/conditional-init.c @@ -0,0 +1,47 @@ +#include <unistd.h> +#include <time.h> +#include <unistd.h> +#include <sys/reboot.h> +#include "../ninitfeatures.h" +#include "../uid.h" + +#define TM_OUT 1200 + +int main(int argc, char **argv) { + unsigned long ul; + char *stable, *test; + + if (argc < 4) { + carp("usage: conditional-init now /stable/init /test/init [args...]\n" + "\tnow must be the output of: date +%s"); + return 1; + } + + errmsg_argv0 = "conditional-init"; + stable=argv[2]; + test=argv[3]; + + if (scan_ulong(argv[1], &ul)==0 || ul + TM_OUT < (unsigned long)time(0)) { + carp("booting (stable): ", stable); + argv += 3; + argv[0] = stable; + execve(stable, argv, environ); + return 0; + } + + if (fork()==0) { + unsigned long deadline = (unsigned long)time(0) + TM_OUT; + while ((unsigned long)time(0) < deadline ) nano_sleep(1,0); + sync(); + set_reboot(RB_AUTOBOOT); + return 2; + } + + argv += 3; + argv[0]=test; + carp("booting (test): ", test); + execve(test, argv, environ); + nano_sleep(TM_OUT,0); /* only if test fails */ + set_reboot(RB_AUTOBOOT); + return 1; +} diff --git a/contrib/env.c b/contrib/env.c new file mode 100644 index 0000000..5bc44bd --- /dev/null +++ b/contrib/env.c @@ -0,0 +1,68 @@ +#include <unistd.h> +#include <alloca.h> +#include "../ninitfeatures.h" +#include "../djb/buffer.h" +#include "../error_table.h" + +static unsigned long env_free; +#include "put_env.h" + +#define BUFFER_1_SIZE 1200 +buffer b = BUFFER_INIT(write, 2, 0, BUFFER_1_SIZE); + +#undef die +#define die(n,...) err_b(&b,__VA_ARGS__,0); buffer_flush(&b); _exit(n) + +int main(int argc,char *argv[]) { + int i; + char *nenv, **env; + + b.x=alloca(BUFFER_1_SIZE); /* XXX if it fails bummer */ + errmsg_iam("env"); + if (environ==0) environ = argv+argc; + for (env=environ; *env; ++env) env_free++; + + env=alloca((argc+env_free+3) * sizeof (char*)); + if (env==0) { die(1, "Out of memory"); } + + byte_copy(env, (env_free+1) * sizeof(char *), environ); + environ = env; + env_free = argc; + + for (i=1; i<argc; ++i) { + char *v=argv[i]; + if (v[0]=='-') { + if (v[1]==0) { + environ[0]=0; + } else { + for (++v; *v; ++v) + switch (*v) { + case 'i': environ[0]=0; break; + case 'u': + if (v[1]) { nenv = v+1; goto do_it; } + else if (argv[++i]) { nenv = argv[i]; goto do_it; } + default: + die(1, "usage: env [-] [-i] [-u] [NAME=VALUE...] " + "[program args...]"); + } + } + } else { + if (v[str_chr(v,'=')]) { nenv = v; goto do_it; } + else { + pathexec_run(v,argv+i,environ); + die(127, "unable ro run: ",v,": ",error_string(table,errno)); + } + } + continue; + + do_it: + put_env(nenv); + } + + for (b.fd = 1; *environ; ++environ) { + buffer_puts(&b, *environ); + buffer_puts(&b, "\n"); + } + buffer_flush(&b); + return 0; +} diff --git a/contrib/put_env.h b/contrib/put_env.h new file mode 100644 index 0000000..0d817b3 --- /dev/null +++ b/contrib/put_env.h @@ -0,0 +1,27 @@ +int put_env(const char *string) { + unsigned int len, envc, remove=0; + char **ep; + + len=str_chr(string,'='); + if (string[len]==0) remove=1; + for (envc=0, ep=environ; *ep; ++ep) { + if (!byte_diff(string, len, *ep) && (*ep)[len]=='=') { + if (remove) { + for (; ep[1]; ++ep) ep[0]=ep[1]; + ep[0]=0; + ++env_free; + return 0; + } + *ep=(char *)string; + return 0; + } + ++envc; + } + if (remove==0) { + if (env_free==0) return -1; + environ[envc++]=(char*)string; + environ[envc]=0; + --env_free; + } + return 0; +} diff --git a/contrib/serdo.c b/contrib/serdo.c new file mode 100644 index 0000000..e45fb9a --- /dev/null +++ b/contrib/serdo.c @@ -0,0 +1,236 @@ +/* serdo.c + modified by Nikola Vladov + unset VAR + exit n + exec file + # comment + ps -ax # comment ps + long line \ + continues here + echo something + . file + VAR=val ... command ... + killall5 -signumber + */ + +#include <unistd.h> +#include <fcntl.h> +#include <ctype.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <time.h> +#include "../ninitfeatures.h" +#include "../error_table.h" + +struct cmd { + char *pos; + char *x; + char last; + char eof; +}; + +static unsigned int env_free, last_cmd; +static char continueonerror; +static int batch(char *s); + +#include "put_env.h" + +static char *e() { return error_string(table, errno); } + +#define str_equal(A,B) !str_diff(A,B) +#define byte_equal(A,l,B) !byte_diff(A,l,B) +#define is_space(c) *c==' ' || (unsigned int)(char)(*c - 9)<5 +#define carpsys(...) err(2,__VA_ARGS__,": ",e(),(char*)0) +#define diesys(n,...) do { err(2,__VA_ARGS__,": ",e(),(char*)0); _exit(n); } while(0) + +#define DQUOTE '"' +#define SQUOTE '\'' + +static void pr_argv(int fd, char **argv) { + char *s; + while ((s=*argv++)) { + unsigned int len = str_len(s); + if (*argv) s[len++] = ' '; + errmsg_put(fd,s,len); + } + errmsg_puts(fd,"\n"); + errmsg_puts(fd,0); +} + +static int pr_fail(char **argv) { + carpsys(argv[0]); + if (argv[1]) pr_argv(2, argv); + return -1; +} + +static void put__env(char *s) { if (put_env(s)) die(1, "Out of memory"); } + +static int spawn(char **argv) { + int i; + char *s0=argv[0], *s1=argv[1], cfg_exec=0, ignore=0; + + if (str_equal(s0,"cd")) { + if (chdir(s1)) return pr_fail(argv); + return 0; + } else if (str_equal(s0,"export") || str_equal(s0,"unset")) { + while (*++argv) put__env(*argv); + return 0; +#ifdef SERDO_WANT_echo + } else if (str_equal(s0,"echo")) { + pr_argv(1, argv+1); + return 0; +#endif + } else if (s1) { + i = x_atoi(s1); + if (str_equal(s0,"exit")) { _exit(i); } + else if (str_equal(s0,"exec")) { cfg_exec++; ++argv; } + else if (s0[0]=='.' && s0[1]==0) { return batch(s1); } +#ifdef SERDO_WANT_killall5 + else if (str_equal(s0,"killall5")) { return kill(-1,-i); } +#endif + } + + if (argv[0][0] == '-') { argv[0] += 1; ignore = 1; } + + if (last_cmd && !cfg_exec) { + struct timespec ts = { 0, 500000000 }; + while ((i=fork()) < 0) nanosleep(&ts, 0); + } else i=-1; /* don't fork */ + + if (i <= 0) { +#ifdef SERDO_WANT_environ_in_command + for (; argv[1]; put__env(*argv++)) { + s0 = argv[0]; + if (!s0[str_chr(s0,'=')]) break; + } +#endif + pathexec_run(*argv,argv,environ); + pr_fail(argv); + if (!i) _exit(-1); /* child */ + return (ignore) ? 0 : -1; + } + + if (waitpid(i,&i,0)==-1) diesys(1,"waitpid failed"); + if (ignore) return 0; + if (!WIFEXITED(i)) return -1; + return WEXITSTATUS(i); +} + +static void get_word(struct cmd *c) { + char ch, *x, *s = c->pos; + + while (is_space(s) || (*s=='\\' && s[1]=='\n')) ++s; + if (!*s) { c->eof |= 1; return; } + c->last=0; + c->x=x=s; + if (*x == '#') c->last |= 2; + + while ((ch=*s)) { + if (ch==DQUOTE || ch==SQUOTE) { + while (*++s) { /* unterminated quoted string <==> *s == 0 */ + if (*s != ch) *x++ = *s; + else { + if (s[-1] == '\\') x[-1] = ch; + else { s++; break; } + } + } + if (!*s) die(2, "syntax error: unexpected EOF"); + } + else if (ch==' ' || ch=='\n' || ch=='\t') break; + else if (ch=='\\' && s[1]=='\n') { s += 2; continue; } + else if (ch=='#') { for (; *s && *s != '\n';) s++; break; } + else *x++ = *s++; + } + while (*s==' ' || *s=='\t') ++s; + if (*s=='\n') { ++s; c->last |= 1; } + + c->pos = s; + if (!*s) c->last |= 1; + *x = 0; +} + +static char *get_argv0(struct cmd *c) { + while (1) { + get_word(c); + if (c->eof) break; + if (c->last & 2) continue; + return c->x; + } + return 0; +} + +static int get_argv(struct cmd *c) { + unsigned int k=0, len=16; + char **argv, first=0; + + argv = alloca((len+2)*sizeof(char*)); + do { + if (first) get_word(c); + else first |= 1; + if (c->eof) break; + if (c->last < 2) { /* comment */ + if (k >= len) { + char **tmp = argv; + len *= 2; + argv = alloca((len+2) * sizeof(char*)); + byte_copy(argv, k*sizeof(char*), tmp); + } + argv[k++] = c->x; + } + } while (!c->last); + argv[k] = 0; + + if (!get_argv0(c)) --last_cmd; + return spawn(argv); +} + +static int execute(struct cmd *c) { + int r = 0; + if (get_argv0(c)) { + ++last_cmd; + + while (1) { + r = get_argv(c); + if (r!=0 && !continueonerror) break; + if (c->eof) break; + } + } + return r; +} + +static int batch(char *s) { + struct cmd c; + int len, fd=open(s,O_RDONLY); + if (fd==-1 || GLOBAL_READ(fd,c.pos, len,32768)) { + carpsys("could not open ",s); + return 1; + } + close(fd); + c.pos[len] = 0; + c.eof = 0; + return execute(&c); +} + +int main(int argc,char* argv[],char* env[]) { + if (argc<2) { +#ifdef SERDO_EXEC_script + if (!access("script",O_RDONLY)) *argv-- = "script"; else +#endif + { ops: die(1,"usage: serdo [-c] file"); } + } + + if (str_equal(argv[1],"-c")) { + ++continueonerror; + ++argv; + } + if (*++argv == 0) goto ops; + errmsg_iam("serdo"); + + for (env_free=0; env[env_free];) ++env_free; + ++env_free; + environ = alloca((env_free + SERDO_MAX_NEW_ENVIRON) * sizeof(char *)); + byte_copy(environ, env_free * sizeof(char *), env); + env_free = SERDO_MAX_NEW_ENVIRON; + + return batch(*argv); +} diff --git a/contrib/sleeprun.c b/contrib/sleeprun.c new file mode 100644 index 0000000..01ea5c9 --- /dev/null +++ b/contrib/sleeprun.c @@ -0,0 +1,65 @@ +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <sys/types.h> +#include <signal.h> +#include "../ninitfeatures.h" +#include "../error_table.h" + +int main(int argc, char **argv) { + int fd; + unsigned long now, interval, last, ul[2] = { 0, 0 }; + char tmp[32],*p; + if (argc<3) + die(1, "usage: sleeprun SleepFile interval [program args...]\n" + "usage: sleeprun -aNumber program [args...]"); + errmsg_iam(argv[0]); + + p = argv[1]; + if (p[0] == '-' && p[1] == 'a') { + scan_ulong(p+2, &interval); + if (interval) alarm(interval); + argv += 2; + goto do_it; + } + + if (read_ulongs(argv[1], ul, 2) > 0) { + errno=0; + if (kill(ul[0],0)==0 || errno != ESRCH) { + tmp[fmt_ulong(tmp, ul[0])] = 0; + carp("WARNING: a program with PID ",tmp," is running now"); + } + } + + last=ul[1]; + scan_ulong(argv[2], &interval); + now = (unsigned long)time(0); + + last += interval; + if (last > now) { + nano_sleep(last-now, 0); + now = (unsigned long)time(0); + } + + if ((fd = open(argv[1], O_WRONLY | O_CREAT | O_TRUNC, 0644)) >=0) { + p = tmp; + p += fmt_ulong(tmp, getpid()); *p++ = ':'; + p += fmt_ulong(p, now); *p++ = 0; + write(fd,tmp,p-tmp); + close(fd); + } + + argv+=3; + do_it: + if (argv[0]) { + char *argv_0 = argv[0]; + argv[0] = argv_0 + str_rchr(argv_0,'/'); + if (argv[0][0]) argv[0]++; + else argv[0]=argv_0; + + pathexec_run(argv_0,argv,environ); + carp("unable to run: ",argv_0,": ",error_string(table, errno)); + return 127; + } + return 0; +} @@ -0,0 +1,27 @@ +#include <time.h> +#include "ninitfeatures.h" + +void cron(char **argv, unsigned long *ret) /*EXTRACT_INCL*/ { + unsigned long a,b,n, cron=0, now=time(0); + unsigned long u[3]; + int dummy; + char *p; + + for (; *argv; argv++) { + p = *argv; + u[2] = 0; + if (scan_ulongs(p,u,3, scan_sec,':',&dummy) < 2) continue; + + if ((a=u[0])==0 || a > (1<<29)) continue; + n = now; + b = u[1]; + + if ((a % 604800) == 0) { b += 3*86400; n -= 3*86400; } + b %= a; + n = n + b - (n % a); + while (n <= now) n += a; + + if (cron==0 || n < cron) { cron = n; ret[1] = u[2]; } + } + ret[0] = cron; +} diff --git a/djb/README b/djb/README new file mode 100644 index 0000000..de175ef --- /dev/null +++ b/djb/README @@ -0,0 +1,2 @@ +ninit uses small string/buffer operations. +In most cases they are less than 15 bytes. diff --git a/djb/atoulong.c b/djb/atoulong.c new file mode 100644 index 0000000..95c96d4 --- /dev/null +++ b/djb/atoulong.c @@ -0,0 +1,7 @@ +unsigned int atoulong(char *s) /*EXTRACT_INCL*/ { + register unsigned int dest=0; + register unsigned char c; + + while ((c=*s-'0')<10) { ++s; dest=dest*10 + c; } + return dest; +} diff --git a/djb/buffer.h b/djb/buffer.h new file mode 100644 index 0000000..dd920f6 --- /dev/null +++ b/djb/buffer.h @@ -0,0 +1,16 @@ +#ifndef BUFFER_H +#define BUFFER_H + +typedef struct buffer { + char *x; /* actual buffer space */ + unsigned int p; /* current position */ + unsigned int n; /* string position */ + unsigned int a; /* allocated buffer size */ + int fd; + int (*op)(); +} buffer; + +#define BUFFER_INIT(op,fd,buf,len) { (buf), 0, 0, (len), (fd), (int (*)())(op) } +#include "../buffer_defs.h" +#include "../byte_defs.h" +#endif diff --git a/djb/buffer_get.c b/djb/buffer_get.c new file mode 100644 index 0000000..ed51707 --- /dev/null +++ b/djb/buffer_get.c @@ -0,0 +1,17 @@ +#include "buffer.h" +#include <errno.h> + +int buffer_getc(buffer* b, char *s) /*EXTRACT_INCL*/ { + if (b->p >= b->n) { + int r; + while ((r=b->op(b->fd, b->x, b->a)) <0) + if (errno != EINTR) break; + + if (r<=0) return r; + b->p = 0; + b->n = r; + } + *s = b->x[b->p]; + b->p++; + return 1; +} diff --git a/djb/buffer_put.c b/djb/buffer_put.c new file mode 100644 index 0000000..f67e98d --- /dev/null +++ b/djb/buffer_put.c @@ -0,0 +1,37 @@ +#include <errno.h> +#include "buffer.h" + +#ifdef USE_BUFFER_LARGE_WRITE +#define X(a) (a>0xffffff)?0xffffff:a +#else +#define X(a) a +#endif + +static int allwrite(buffer *b, const char *buf, unsigned int len) { + int w; + b->p = 0; + while (len) { + w = b->op(b->fd, buf, X(len)); + if (w == -1) { + if (errno == EINTR) continue; + return -1; + } + buf += w; + len -= w; + } + return 0; +} + +int buffer_flush(buffer *b) /*EXTRACT_INCL*/ { + return allwrite(b,b->x,b->p); +} + +int buffer_put(buffer *b, const char* s, unsigned int len) /*EXTRACT_INCL*/ { + if (b->a-b->p < len) { + if (buffer_flush(b)==-1) return -1; + if (b->a < len) return allwrite(b, s, len); + } + byte_copy(b->x + b->p, len, s); + b->p += len; + return 0; +} diff --git a/djb/buffer_putc.c b/djb/buffer_putc.c new file mode 100644 index 0000000..5ed0689 --- /dev/null +++ b/djb/buffer_putc.c @@ -0,0 +1,5 @@ +#include "buffer.h" + +int buffer_putc(buffer *b, char ch) /*EXTRACT_INCL*/ { + return buffer_put(b, &ch, 1); +} diff --git a/djb/buffer_puts.c b/djb/buffer_puts.c new file mode 100644 index 0000000..0a8696e --- /dev/null +++ b/djb/buffer_puts.c @@ -0,0 +1,6 @@ +#include "buffer.h" + +int buffer_puts(buffer *b, const char* s) /*EXTRACT_INCL*/ { + return buffer_put(b, s, str_len(s)); +} + diff --git a/djb/byte_copy.c b/djb/byte_copy.c new file mode 100644 index 0000000..84d9f45 --- /dev/null +++ b/djb/byte_copy.c @@ -0,0 +1,7 @@ +void byte_copy(void *to, unsigned int n, const void *from) /*EXTRACT_INCL*/ { + char *d=(char*)to; + char *s=(char*)from; + unsigned int k=0; + for (; k<n; k++) d[k] = s[k]; +} + diff --git a/djb/byte_copyr.c b/djb/byte_copyr.c new file mode 100644 index 0000000..9574ae7 --- /dev/null +++ b/djb/byte_copyr.c @@ -0,0 +1,8 @@ +void byte_copyr(void* dst, unsigned int n, const void* src) /*EXTRACT_INCL*/ { + char *d=(char*)dst; + char *s=(char*)src; + while (n) { + --n; + d[n] = s[n]; + } +} diff --git a/djb/byte_diff.c b/djb/byte_diff.c new file mode 100644 index 0000000..6ad0a13 --- /dev/null +++ b/djb/byte_diff.c @@ -0,0 +1,11 @@ +int byte_diff(const void* a, unsigned int len, const void* b) /*EXTRACT_INCL*/ { + char *x=(char *)a; + char *y=(char *)b; + unsigned int u=0; + char ch=0; + for (; u<len; u++) { + ch = x[u] - y[u]; + if (ch) break; + } + return ch; +} diff --git a/djb/byte_set.c b/djb/byte_set.c new file mode 100644 index 0000000..0248efa --- /dev/null +++ b/djb/byte_set.c @@ -0,0 +1,7 @@ +void byte_set(const void* dst, unsigned int len, char ch) /*EXTRACT_INCL*/ { + char *d=(char*)dst; + while (len) { + --len; + d[len] = ch; + } +} diff --git a/djb/byte_zero.c b/djb/byte_zero.c new file mode 100644 index 0000000..1fba78a --- /dev/null +++ b/djb/byte_zero.c @@ -0,0 +1,7 @@ +void byte_zero(void *to, unsigned int k) /*EXTRACT_INCL*/ { + char *d = (char *)to; + while (k) { + k--; + d[k] = 0; + } +} diff --git a/djb/env_get.c b/djb/env_get.c new file mode 100644 index 0000000..f84a1fa --- /dev/null +++ b/djb/env_get.c @@ -0,0 +1,15 @@ +#include "../byte_defs.h" +extern char **environ; + +char *env_get(const char *s) /*EXTRACT_INCL*/ { + int i; + unsigned int slen; + char *envi; + + if (environ==0) return 0; + slen = str_len(s); + for (i = 0; (envi = environ[i]); ++i) + if ((!byte_diff(s,slen,envi)) && (envi[slen] == '=')) + return envi + slen + 1; + return 0; +} diff --git a/djb/fmt_str.c b/djb/fmt_str.c new file mode 100644 index 0000000..3843311 --- /dev/null +++ b/djb/fmt_str.c @@ -0,0 +1,8 @@ +unsigned int fmt_str(char *s, const char *t) /*EXTRACT_INCL*/ { + register unsigned int len; + char ch; + len = 0; + if (s) { while ((ch = t[len])) s[len++] = ch; } + else while (t[len]) len++; + return len; +} diff --git a/djb/fmt_ulong.c b/djb/fmt_ulong.c new file mode 100644 index 0000000..dfd7f9e --- /dev/null +++ b/djb/fmt_ulong.c @@ -0,0 +1,10 @@ +unsigned int fmt_ulong(char *s, unsigned long u) /*EXTRACT_INCL*/ { + register unsigned int len; register unsigned long q; + len = 1; q = u; + while (q > 9) { ++len; q /= 10; } + if (s) { + s += len; + do { *--s = '0' + (u % 10); u /= 10; } while(u); /* handles u == 0 */ + } + return len; +} diff --git a/djb/scan_8ulong.c b/djb/scan_8ulong.c new file mode 100644 index 0000000..1999e29 --- /dev/null +++ b/djb/scan_8ulong.c @@ -0,0 +1,5 @@ +#include "scan_number.h" +SCAN_NUMBER_DEFINE(scan_8ulong, unsigned long, 8) +#if 0 +unsigned int scan_8ulong(const char *s, unsigned long *u) /*EXTRACT_INCL*/ +#endif diff --git a/djb/scan_number.h b/djb/scan_number.h new file mode 100644 index 0000000..17e1586 --- /dev/null +++ b/djb/scan_number.h @@ -0,0 +1,9 @@ +#define SCAN_NUMBER_DEFINE(name, type, base) \ +unsigned int name(const char *s, type *u) {\ + unsigned int pos;\ + type result, c;\ + pos = 0; result = 0;\ + while ((c = (type) (unsigned char) (s[pos] - '0')) < base)\ + { result = result * base + c; ++pos; }\ + *u = result; return pos;\ +} diff --git a/djb/scan_ulong.c b/djb/scan_ulong.c new file mode 100644 index 0000000..8f240a8 --- /dev/null +++ b/djb/scan_ulong.c @@ -0,0 +1,5 @@ +#include "scan_number.h" +SCAN_NUMBER_DEFINE(scan_ulong, unsigned long, 10) +#if 0 +unsigned int scan_ulong(const char *s, unsigned long *u) /*EXTRACT_INCL*/ +#endif diff --git a/djb/str_chr.c b/djb/str_chr.c new file mode 100644 index 0000000..1506f30 --- /dev/null +++ b/djb/str_chr.c @@ -0,0 +1,6 @@ +unsigned int str_chr(const char *in, char needle) /*EXTRACT_INCL*/ { + unsigned int u=0; + char ch; + while ((ch=in[u]) && ch != needle) u++; + return u; +} diff --git a/djb/str_copy.c b/djb/str_copy.c new file mode 100644 index 0000000..90d2da6 --- /dev/null +++ b/djb/str_copy.c @@ -0,0 +1,5 @@ +unsigned int str_copy(char *out,const char *in) /*EXTRACT_INCL*/ { + unsigned int len=0; + while ((out[len]=in[len])) len++; + return len; +} diff --git a/djb/str_copyn.c b/djb/str_copyn.c new file mode 100644 index 0000000..3dab724 --- /dev/null +++ b/djb/str_copyn.c @@ -0,0 +1,6 @@ +unsigned int str_copyn(char *out,const char *in, unsigned int len) /*EXTRACT_INCL*/ { + unsigned int k=0; + while (k<len && (out[k]=in[k])) k++; + if (k<len) out[k] = 0; + return k; +} diff --git a/djb/str_diff.c b/djb/str_diff.c new file mode 100644 index 0000000..2c5ba59 --- /dev/null +++ b/djb/str_diff.c @@ -0,0 +1,11 @@ +int str_diff(const char* a, const char* b) /*EXTRACT_INCL*/ { + unsigned int u=0; + char ch=0; + for (;; u++) { + ch = a[u]-b[u]; + if (ch) break; + if (a[u]==0) break; + } + return ch; +} + diff --git a/djb/str_diffn.c b/djb/str_diffn.c new file mode 100644 index 0000000..934040f --- /dev/null +++ b/djb/str_diffn.c @@ -0,0 +1,11 @@ +int str_diffn(const char* a, const char* b, unsigned int limit) /*EXTRACT_INCL*/ { + unsigned int u=0; + char ch=0; + + for (; u<limit; u++) { + ch = a[u] - b[u]; + if (ch) break; + if (a[u]==0) break; + } + return ch; +} diff --git a/djb/str_len.c b/djb/str_len.c new file mode 100644 index 0000000..9ce761a --- /dev/null +++ b/djb/str_len.c @@ -0,0 +1,5 @@ +unsigned int str_len(const char * s) /*EXTRACT_INCL*/ { + unsigned int len=0; + while (s[len]) ++len; + return len; +} diff --git a/djb/str_rchr.c b/djb/str_rchr.c new file mode 100644 index 0000000..ce7ab37 --- /dev/null +++ b/djb/str_rchr.c @@ -0,0 +1,9 @@ +unsigned int str_rchr(const char *in, char needle) /*EXTRACT_INCL*/ { + char ch; + unsigned int u=0, found = (unsigned int)-1; + for (;; u++) { + if ((ch=in[u])==0) break; + if (ch==needle) found=u; + } + return (found != (unsigned int)-1) ? found : u; +} diff --git a/error_table.h b/error_table.h new file mode 100644 index 0000000..8221a90 --- /dev/null +++ b/error_table.h @@ -0,0 +1,19 @@ +#include <errno.h> + +static struct error_table table[] = { + {EACCES, "Permission denied"}, + {EINVAL, "Invalid argument"}, + {EIO, "I/O error"}, + {EISDIR, "Is a directory"}, + {ELOOP, "Too many symbolic links"}, + {ENAMETOOLONG, "File name too long"}, + {ENOENT, "No such file or directory"}, + {ENOEXEC, "Exec format error"}, + {ENOMEM, "Out of memory"}, + {ENOSYS, "Function not implemented"}, + {ENOTDIR, "Not a directory"}, + {EROFS, "Read-only file system"}, + {ETXTBSY, "Text file busy"}, + {ESPIPE, "Illegal seek"}, + {0,0} +}; diff --git a/findservice.h b/findservice.h new file mode 100644 index 0000000..29f3f1a --- /dev/null +++ b/findservice.h @@ -0,0 +1,24 @@ +#ifdef INIT_PROGRAM +static void circsweep() { + int i; + for (i=0; i<=maxprocess; i++) + root[i].pr_circular=0; +} +#endif + + +/* return index of service in process data structure or -1 if not found */ +static int findservice(char *service) { + int i; + + for (i=0; i<=maxprocess; ++i) { +#if defined (INIT_PROGRAM) && ! defined (INIT_BLACK) + char *x=root_name(i), *y=service; + while (*x == *y && *x) { x++; y++; } + if (*x==*y) return i; +#else + if (!str_diff(root_name(i), service)) return i; +#endif + } + return -1; +} diff --git a/get_headers b/get_headers new file mode 100755 index 0000000..a18b474 --- /dev/null +++ b/get_headers @@ -0,0 +1,25 @@ +#!/bin/sh +[ $# -lt 2 ] && exit 1 + +export PATH=/bin:/usr/bin +name=`echo $1 | sed -e 's/\./__DOT__/g' -e 's/\//__SLASH__/g'` +shift + +echo '#ifndef' AUTO_FILE__$$__$name +echo '#define' AUTO_FILE__$$__$name +echo '/* '`date`' */' + +while test $# -gt 0; do + case $1 in + -L*) echo $1 | sed -e 's/^../#include "/' -e 's/$/"/' ; shift;; + -G*) echo $1 | sed -e 's/^../#include </' -e 's/$/>/' ; shift;; + -I*) echo $1 | sed -e 's/^../#include /'; shift;; + *) break;; + esac +done + +if [ $# -gt 0 ] ; then + sed -n -e 's/\(.*\) \/\*EXTRACT_INCL\*\/.*/extern \1;/p' \ + -e 's/ \/\*EXTRACT_UNMOD\*\/.*//p' $@ +fi +echo '#endif' diff --git a/get_services.h b/get_services.h new file mode 100644 index 0000000..d64ae55 --- /dev/null +++ b/get_services.h @@ -0,0 +1,91 @@ +#include "djb/buffer.h" + +buffer b_outfd = BUFFER_INIT(read, -1, 0, BUFFER_TMP_LEN); +static unsigned short maxhistory; +static unsigned short *history; + +#ifdef UNKNOWN_PROCESS_SIZE +static unsigned int process_size; +#else +#define process_size PROCESS_SIZE +#endif + +#define MAX_SERVICE_NAME 256 + +/* read from outfd string or constant lenght*/ +int read_stringb(char *s,int len) { + int count=0; + while (1) { + if (buffer_getc(&b_outfd, s+count) <=0 ) break; + if (len==-1 && s[count]==0) return count; + ++count; + if (count==len) return count; + if (len==-1 && count==MAX_SERVICE_NAME) break; + } + die_xx("error getting data"); + return -1; +} + +/* buf[??] is defined in the main program */ +void get_services() { + int j; + char x[MAX_SERVICE_NAME + PROCESS_SIZE], *tmp, *name=""; + + if (root) return; + b_outfd.x = buf; + b_outfd.fd = outfd; + x[0] = 'D', x[1]='0'; + if (do_update) x[1]='1'; /* XXX D1 set doupdate */ + write(infd,x,2); + + /* 1. names */ + while (1) { + j = read_stringb(x,-1); + if (j==0) break; + if ((int)mem.r <= j + PROCESS_SIZE) die_xx("Out of memory"); + mem.r -= ++j; + name = mem.x + mem.r; + byte_copy(name, j, x); + ++maxprocess; + } + + /* 2. history */ + read_stringb(x, sizeof(unsigned short) - 1); + maxhistory = (unsigned char)x[0]; + j = sizeof(unsigned short) * maxhistory; + +#ifdef UNKNOWN_PROCESS_SIZE + if (process_size && maxprocess >= 0) { + process_size -= (mem.a-mem.r) + j + sizeof(unsigned short); + process_size /= (maxprocess+1); + byte_zero(mem.x, mem.r); + } else + process_size = PROCESS_SIZE; +#endif + + mem.r -= (mem.r % 8); + if (j) { + if ((int)mem.r < j) die_xx("Out of memory"); + mem.r -= j; + tmp = mem.x + mem.r; + read_stringb(tmp,j); + history = (unsigned short *)tmp; + } + + /* 3. processes */ + mem.l = (maxprocess+1) * PROCESS_SIZE; + mem.r -= (mem.r % 16); + if (mem.l >= mem.r) die_xx("Out of memory"); + tmp = mem.x + mem.r - mem.l; + root = (struct process *)tmp; + + for (j=0; j<=maxprocess; j++) { + read_stringb(tmp, process_size); + tmp += PROCESS_SIZE; + root[j].pr_circular = 0; + root[j].name = alloc_name_set(name); + name += str_len(name) + 1; + } +} + +#undef MAX_SERVICE_NAME diff --git a/home.tar.gz b/home.tar.gz Binary files differnew file mode 100644 index 0000000..3051812 --- /dev/null +++ b/home.tar.gz diff --git a/initreq.h b/initreq.h new file mode 100644 index 0000000..6f6547b --- /dev/null +++ b/initreq.h @@ -0,0 +1,77 @@ +/* + * initreq.h Interface to talk to init through /dev/initctl. + * + * Copyright (C) 1995-2004 Miquel van Smoorenburg + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * Version: @(#)initreq.h 1.28 31-Mar-2004 MvS + * + */ +#ifndef _INITREQ_H +#define _INITREQ_H + +#include <sys/param.h> + +#if defined(__FreeBSD_kernel__) +# define INIT_FIFO "/etc/.initctl" +#else +# define INIT_FIFO "/dev/initctl" +#endif + +#define INIT_MAGIC 0x03091969 +#define INIT_CMD_START 0 +#define INIT_CMD_RUNLVL 1 +#define INIT_CMD_POWERFAIL 2 +#define INIT_CMD_POWERFAILNOW 3 +#define INIT_CMD_POWEROK 4 +#define INIT_CMD_BSD 5 +#define INIT_CMD_SETENV 6 +#define INIT_CMD_UNSETENV 7 + +#define INIT_CMD_CHANGECONS 12345 + +#ifdef MAXHOSTNAMELEN +# define INITRQ_HLEN MAXHOSTNAMELEN +#else +# define INITRQ_HLEN 64 +#endif + +/* + * This is what BSD 4.4 uses when talking to init. + * Linux doesn't use this right now. + */ +struct init_request_bsd { + char gen_id[8]; /* Beats me.. telnetd uses "fe" */ + char tty_id[16]; /* Tty name minus /dev/tty */ + char host[INITRQ_HLEN]; /* Hostname */ + char term_type[16]; /* Terminal type */ + int signal; /* Signal to send */ + int pid; /* Process to send to */ + char exec_name[128]; /* Program to execute */ + char reserved[128]; /* For future expansion. */ +}; + + +/* + * Because of legacy interfaces, "runlevel" and "sleeptime" + * aren't in a seperate struct in the union. + * + * The weird sizes are because init expects the whole + * struct to be 384 bytes. + */ +struct init_request { + int magic; /* Magic number */ + int cmd; /* What kind of request */ + int runlevel; /* Runlevel to change to */ + int sleeptime; /* Time between TERM and KILL */ + union { + struct init_request_bsd bsd; + char data[368]; + } i; +}; + +#endif diff --git a/inittab.c b/inittab.c new file mode 100644 index 0000000..0e18e5f --- /dev/null +++ b/inittab.c @@ -0,0 +1,374 @@ +#include <unistd.h> +#include <fcntl.h> +#include <stdlib.h> +#include <errno.h> +#include "ninitfeatures.h" +#include "initreq.h" +#include "djb/buffer.h" + +#define out(...) err_b(buffer_out,__VA_ARGS__,(char*)0); +#define outs(X) buffer_puts(buffer_out, X) +#define outc(X) buffer_putc(buffer_out, X) + +char buffer_out_space[4096]; +buffer b_out = BUFFER_INIT(write, -1, buffer_out_space, 4096); + +buffer *buffer_out = &b_out; + +struct ientry { + char *id; + char *level; + char *action; + char **argv; +}; + +char *home, *initscript=0, *app_f=0; +int fd; + +void step(char *s) + { out("test -d ",s," || mkdir ",s," ; cd ",s," || ops ",s); } + +void out_octal(unsigned char x) { + outc('\\'); outc('0' + (x>>6)); + outc('0' + ((x>>3)&7)); outc('0' + (x&7)); +} + +void out_txt(char *s) { + unsigned char x; + while ((x=*s++)) { + if (('a' <= x && x<= 'z') || + ('A' <= x && x<= 'Z') || x==' ' || x=='/') outc(x); + else out_octal(x); + } +} + +void append(char *m) { + outs("printf \""); + out_txt(m); + outs("\\012\""); + if (app_f) + { out(" >> ",app_f); } +} + +void rm_all() { out("rm_old"); } + +void stop_respawn() { + app_f = "setup"; + append("#!/bin/sh\n" + "all=`/bin/nsvc -L`\n" + "/bin/nsvc -C0 $all\n" + "exec /bin/nsvc -r $all"); + out("chmod 755 setup ; rm -f sync"); +} + +void mk_run(char **xx) { + out("ln -s ",*xx++," run"); + app_f = 0; + if (*xx==0) return; + outs("printf \""); + while (*xx) { out_txt(*xx++); out_txt("\n"); } + outs("\" > params\n"); +} + +void check_file(char *mode, char *file) +{ out("test ",mode," ",file," || echo '*** Missing file:' ",home,"/",file);} + +void check_utmp(char *utmp_file) { + out("if test ! -f ",utmp_file," ; then"); + out(" echo '*** WARNING *** Missing file:' ", utmp_file); + out(" echo 'ninit stores in last file the variable INIT_RUNLEVEL'"); + out(" echo 'ninit does not use this variable. Some other programs'"); + out(" echo 'can use it (scripts from /etc/init.d/). If you have'"); + out(" echo 'some troubles, create this file latter!'"); + out("fi\n"); +} + +void die_mem() { die(111,"Out of memory"); } + +int main(int Argc, char **Argv) { + static char *initdefault; + int seen_pf=-1, seen_pw=-1, seen_pn=-1, seen_po=-1; + int seen_cad=-1, seen_kbr=-1; + int seen_l0=-1, seen_l6=-1; + char *p,*s,*service,**argv; + int len,argc,k,j; + struct ientry *qq,ee; + + s = Argv[1]; + if (s && s[0]=='-' && s[1]=='I' && s[2]) { + initscript = s+2; + Argv++; Argc--; + } + + if (Argc<4 || Argv[2][0] == 0) + { die(100,"usage: ninit-inittab [-I/etc/initscript] /etc/inittab "INITROOT" output_file"); } + home = Argv[2]; + + if ((fd = open(Argv[1], O_RDONLY)) <0) + { die(100, "error opening: ",Argv[1]); } + + if (GLOBAL_READ(fd,s, len,128000)) + { die(1, "error reading: ", Argv[1]); } + close(fd); + s[len]=0; + + if ((fd = open(Argv[3], O_CREAT|O_TRUNC|O_WRONLY, 0755)) <0) + { die(100, "error opening: ",Argv[3]); } + buffer_out->fd = fd; + + argc = splitmem(0,s,'\n'); + argv=alloca((len+1) * sizeof(char*)); if (argv==0) die_mem(); + splitmem(argv,s,'\n'); + + for (len=0,k=0; argv[k]; k++) { + s=argv[k]; + if (*s=='#' || *s==0) continue; + ++len; + } + + qq = alloca((len+2)*sizeof(struct ientry)); if (qq==0) die_mem(); + + msg("\tvalid ",Argv[1]," entries"); + for (len=0,k=0; argv[k]; k++) { + char **zz; + s=argv[k]; + if (*s == '#' || *s==0) continue; + byte_zero(&ee, sizeof(struct ientry)); + + ee.id = s; + s += str_chr(s,':'); if (*s==0) continue; *s++ = 0; + ee.level = s; + s += str_chr(s,':'); if (*s==0) continue; *s++ = 0; + ee.action = s; + s += str_chr(s,':'); if (*s==0) continue; *s++ = 0; + + msg(ee.id,":",ee.level,":",ee.action,":",s); + if (!str_diff(ee.action, "initdefault")) + initdefault = ee.level; + if (*s==0) continue; + + zz = alloca(40 * sizeof(char*)); if (zz==0) die_mem(); + zz += 40; + *--zz = 0; + + /* See if there is an "initscript" (except in single user mode). */ + if (initscript && str_diff("S",ee.level)) { + /* Build command line using "initscript" */ + *--zz = s; + *--zz = ee.action; + *--zz = ee.level; + *--zz = ee.id; + *--zz = initscript; + *--zz = "/bin/sh"; + ee.argv = zz; + } else if (strpbrk(s, "~`!$^&*()=|\\{}[];\"'<>?")) { + /* See if we need to fire off a shell for this command */ + *--zz = s; + *--zz = "-c"; + *--zz = "/bin/sh"; + ee.argv = zz; + } else { + /* Split up command line arguments */ + int f; + zz -= 22; + ee.argv = zz; + for (f = 0; f < 20; f++) { + while(*s == ' ' || *s == '\t') s++; + zz[f] = s; + + if (*s == 0) break; + while (*s && *s != ' ' && *s != '\t' && *s != '#') s++; + + if (*s == '#' || *s == 0) { + f++; + *s = 0; + break; + } + *s++ = 0; + } + zz[f] = 0; + } + + byte_copy(&qq[len], sizeof(ee), &ee); + ++len; + } + for (k=0; k<len; k++) + for (j=k+1; j<len; j++) + if (!str_diff(qq[k].id, qq[j].id)) { + msg(" \a*** WARNING *** ", Argv[1],": duplicated id: ",qq[k].id); + } + + if (initdefault==0) { die(100, "unable to find initdefault level"); } + + /* -------------- change bellow this line ---------------- */ + out("#!/bin/sh\n" + "# WARNING: This file was auto-generated.\n" + "# Source: ",Argv[1], + "\n\nexport PATH=/bin:/usr/bin\n" + "umask 022\n" + "ops () { echo cd error $1; exit 1; }\n" + "rm_old () { rm -f run sync setup params respawn; }\n"); + + check_utmp("/var/run/utmp"); + + step(home); + check_file("-d","sys"); + check_file("-x","sys/run"); + check_file("-x","sys/run-wait"); + check_file("-x","sys/update"); + check_file("-x","sys/procfs"); + check_file("-x","sys/remove"); + check_file("-p","in"); + check_file("-p","out"); + + out("\nif test -f .services_ready; then\n" + " echo Please read ",home,"/.services_ready\n" + " exit 1\nfi\n"); + + out("test -d default || mkdir default\n" + "test -f default/depends && " + "mv -f default/depends default/depends.old\n" + "rm -f default/depends\n"); + + step("sysvinit"); + rm_all(); + out("ln -sf /sbin/ninit-sysvinit run"); + app_f = "sysvinit-timeout"; + append("90:0\n" + "DO NOT remove or rename this file\n" + "unless you know what are you doing!"); + out("cd ..\n"); + + step("powerS"); + rm_all(); + out("ln -sf /sbin/ninit-sysvinit run\n" + "echo powerS > params"); + out("cd ..\n"); + + step("update"); + rm_all(); + out("ln -sf /sbin/ninit-reload run"); + app_f = "params"; + append("-v\n-Rupdate\n-a30\n-u\n/sbin/ninit"); + out("cd ..\n", + "ln -sf update level","U\n", + "ln -sf update level","Q\n"); + + step("ngetty"); + rm_all(); + out("ln -s /sbin/ngetty run"); + app_f = "params"; + append("1\n2\n3\n4\n5\n6"); + out("> respawn"); + app_f = "environ"; + append("\nTERM=linux"); + out("cd ..\n"); + + + for (k=0; k<len; k++) { + char **xx; + byte_copy(&ee, sizeof(ee), &qq[k]); + xx=ee.argv; + if (!str_diff(ee.action, "off")) { + msg("\tskipping entry\t", ee.id,":",ee.level,":",ee.action,": ..."); + continue; + } + + service = alloca(4+str_len(ee.id)); if (service==0) die_mem(); + service[0]='_'; + str_copy(service+1,ee.id); + + if (!str_diff(ee.action, "ctrlaltdel")) { seen_cad = k; } + else if (!str_diff(ee.action, "kbrequest")) { seen_kbr = k; } + else if (!str_diff(ee.action, "sysinit") || + !str_diff(ee.action, "boot") || + !str_diff(ee.action, "bootwait") || + !str_diff(ee.action, "once") || + !str_diff(ee.action, "powerfail") || + !str_diff(ee.action, "powerwait") || + !str_diff(ee.action, "powerfailnow") || + !str_diff(ee.action, "powerokwait")) { + step(service); + rm_all(); + if (ee.action[0] == 's' || ee.action[4] == 'w') out("> sync"); + mk_run(xx); + out("cd ..\n"); + if (ee.action[0] != 'p') { + app_f = "default/depends\n"; + append(service); + } + if (!str_diff(ee.action, "powerfail")) { seen_pf = k; } + if (!str_diff(ee.action, "powerwait")) { seen_pw = k;} + if (!str_diff(ee.action, "powerfailnow")) { seen_pn = k; } + if (!str_diff(ee.action, "powerokwait")) { seen_po = k; } + } + else { + step(service); + rm_all(); + if (!str_diff(ee.action, "wait")) { + p = ee.level; + out("> sync"); + if (p[0] && p[1]==0) { + if (*p=='0') { seen_l0=k; stop_respawn(); } + if (*p=='6') { seen_l6=k; stop_respawn(); } + *--xx = p; + *--xx = "/sbin/ninit-runlevel"; + } + } + if (!str_diff(ee.action,"respawn")) { + out("> respawn"); + if (strstr(ee.argv[0],"getty")) { + *--xx = ee.id; + *--xx = "/sbin/pututmpid"; + } + } + mk_run(xx); + out("cd ..\n"); + + if (!str_diff(ee.action, "wait")) { + p = ee.level; + if (p[0] && p[1]==0) out("ln -s ",service," level",p, "\n"); + } + + s = ee.level; + s += str_chr(s, *initdefault); + if (*s) { + app_f = "default/depends\n"; + append(service); + } + } + } + + s = "ln -sf _"; + if (seen_kbr>=0 && seen_l6>=0) out(s,qq[seen_l6].id," kbreq"); + if (seen_cad>=0 && seen_l0>=0) out(s,qq[seen_l0].id," ctrlaltdel"); + + if (seen_l0>=0) out(s,qq[seen_l0].id," halt"); + if (seen_l6>=0) out(s,qq[seen_l6].id," reboot"); + + /* XXX powerfail or powerwait ??? ; first may be ;-) */ + if (seen_pf>=0 && seen_pf < seen_pw) out(s,qq[seen_pf].id," powerF"); + if (seen_pw>=0 && seen_pw < seen_pf) out(s,qq[seen_pw].id," powerF"); + + if (seen_pn>=0) out(s,qq[seen_pn].id," powerL"); + if (seen_po>=0) out(s,qq[seen_po].id," powerO"); + out(""); + + out("test -d _l0 && echo INIT_HALT=POWERDOWN > _l0/environ\n" + "if test -d _l6 ; then"); + app_f = "_l6/environ"; + append("#INIT_HALT=POWERDOWN\n" + "#INIT_HALT=HALT\n" + "INIT_HALT"); + out("fi\n"); + + app_f = ".services_ready"; + append("*** WARNING ***\n" + "Someone made services in this directory.\n" + "If you want to overwrite them remove me.\n"); + + buffer_flush(buffer_out); + + close(fd); + return 0; +} diff --git a/install-bin.c b/install-bin.c new file mode 100644 index 0000000..fc18b07 --- /dev/null +++ b/install-bin.c @@ -0,0 +1,129 @@ +#include <unistd.h> +#include <fcntl.h> +#include <alloca.h> +#include <stdio.h> +#include <sys/stat.h> +#include "ninitfeatures.h" +#include "error_table.h" +#include "uid.h" + +#define U "unable to " + +static char *e() { return error_string(table, errno); } +static void nomem() { die(111,"out of memory"); } +static void ex(char *s0, char *s1) { die(111,U,s0,": ",s1,": ",e()); } + +static void doit(char *to, char *line) { + char *x, **arg, *target, *tmp; + char *type, *mid, *name, *alias; + unsigned long uid, gid, mode; + int in, out, len; + static char *uid_global, *gid_global, *mode_global, *mid_global, V; + + len=splitmem(0,line,':'); if (len <7) return; + arg=alloca((len+1) * sizeof(char*)); if (arg==0) nomem(); + splitmem(arg,line,':'); + + type = arg[0]; + x=arg[1]; if (!*x==0 && uid_global) x=uid_global; + if (*x) uid=atoulong(x); else uid = -1; + + x=arg[2]; if (!*x==0 && gid_global) x=gid_global; + if (*x) gid=atoulong(x); else gid = -1; + + x=arg[3]; if (!*x && mode_global) x=mode_global; scan_8ulong(x,&mode); + mid = arg[4]; if (!*mid && mid_global) mid=mid_global; + name= arg[5]; + x=arg[6]; alias = (*x) ? x : name; + + len = str_len(to) + str_len(mid) + str_len(name); + x=alloca(2*len + 32); if (x==0) nomem(); + target = x; + x += str_copy(x,to); + x += str_copy(x,mid); + x += str_copy(x,name); + while (target[0]=='/' && target[1]=='/') target++; + tmp = (*type=='x') ? x+2 : 0; + + switch(*type) { + case 'p': + if (SYS_mknod(target,S_IFIFO|0600,0) == -1) + if (errno != EEXIST) ex("mknod",target); + if (V) msg("pipe:\t", target); + break; + + case 'd': + if (mkdir(target,0700) == -1) + if (errno != EEXIST) ex("mkdir",target); + if (V) msg("mkdir:\t", target); + break; + + case 'c': + case 'x': + if ((in=open(alias, O_RDONLY)) <0) ex("open",alias); + + if (*type == 'c') out = open(target, O_WRONLY|O_CREAT|O_TRUNC, 0600); + else out = open_tmpfd(target, tmp, 0600); + if (out <0) ex("open",target); + + x=alloca(8192); if (x==0) nomem(); + for (;;) { + len=read(in,x,8192); + if (len==0) break; + else if (len==-1) ex("read",alias); + else if (len != write(out,x,len)) { die(111,U,"write",target); } + } + + close(in); + if (fsync(out)) ex("fsync",target); + if (close(out)) ex("close",target); + if (tmp && rename(tmp,target)) + { die(111,U,"rename: ", tmp, " -> ", target, ": ", e()); } + if (V) msg(alias, "\t-> ", target); + break; + + case 'g': + x=arg[1]; uid_global = (*x) ? x : 0; + x=arg[2]; gid_global = (*x) ? x : 0; + x=arg[3]; mode_global = (*x) ? x : 0; + x=arg[4]; mid_global = (*x) ? x : 0; + return; + + case 'v': + if (arg[1][0]) V=1; + else V=0; + + default: + return; + } + if (SYS_chown(target,uid,gid) <0) ex("chown",target); + if (chmod(target,mode) <0) ex("chmod",target); +} + +int main(int argc, char **argv) { + char *to, **arg, *s=0; + if (argc<2) { die(100,"usage: install-bin Dir < File\n " + "install-bin Dir c:::755:mid:file:: x:::755:mid:name:source: ...\n" + "File contains lines:\ntype:uid:gid:mode:middle:target:source:\n" + "type is one of the letters: vpdcxg\n" + "type g sets global uid:gid:mode:middle\n"); } + + to = argv[1]; + errmsg_iam("install-bin"); + umask(077); + + if (argc == 2) { + int len; + if (GLOBAL_READ(0,s, len,100000)) ex("read","stdin"); + close(0); + s[len]=0; + + len = splitmem(0,s,'\n'); + arg = alloca((len+1) * sizeof(char*)); if (arg==0) nomem(); + splitmem(arg,s,'\n'); + } else + arg = argv+2; + + for (; (s=*arg); ++arg) doit(to, s); + return 0; +} diff --git a/lib/do_wtmp.c b/lib/do_wtmp.c new file mode 100644 index 0000000..1799895 --- /dev/null +++ b/lib/do_wtmp.c @@ -0,0 +1,11 @@ +#include <unistd.h> +#include <fcntl.h> +#include <utmp.h> + +void do_wtmp(struct utmp *utmp) /*EXTRACT_INCL*/ { + int fd; + if ((fd=open(_PATH_WTMP, O_WRONLY | O_APPEND)) >= 0) { + write(fd, utmp, sizeof(struct utmp)); + close(fd); + } +} diff --git a/lib/err.c b/lib/err.c new file mode 100644 index 0000000..fd4218e --- /dev/null +++ b/lib/err.c @@ -0,0 +1,39 @@ +#include <stdarg.h> +#include "../ninitfeatures.h" +#include "../djb/buffer.h" + +#if 0 +void err(int fd, const char *m, ...) /*EXTRACT_INCL*/ +#endif + +#ifdef ERRMSG_BUFFER +#define P(S) buffer_puts(X,S) +#define E() err_b(buffer *X, const char *m, ...) + +#else +#define P(S) errmsg_puts(X,S) +#define E() err(int X, const char *m, ...) +#endif + +extern const char *errmsg_argv0; + +void E() { + const char *s=m; + va_list a; + va_start(a,m); + + if (errmsg_argv0) { + P(errmsg_argv0); + P(": "); + } + + while (s) { + P(s); + s=va_arg(a,const char*); + } + P("\n"); +#ifndef ERRMSG_BUFFER + P(0); +#endif + va_end(a); +} diff --git a/lib/err_b.c b/lib/err_b.c new file mode 100644 index 0000000..2de7017 --- /dev/null +++ b/lib/err_b.c @@ -0,0 +1,5 @@ +#define ERRMSG_BUFFER +#include "err.c" +#if 0 +void err_b(buffer *b, const char *m, ...) /*EXTRACT_INCL*/ +#endif diff --git a/lib/errmsg_argv0.c b/lib/errmsg_argv0.c new file mode 100644 index 0000000..ef63ea9 --- /dev/null +++ b/lib/errmsg_argv0.c @@ -0,0 +1 @@ +const char *errmsg_argv0=0; diff --git a/lib/errmsg_put.c b/lib/errmsg_put.c new file mode 100644 index 0000000..9afe0ce --- /dev/null +++ b/lib/errmsg_put.c @@ -0,0 +1,20 @@ +#include <sys/uio.h> +#include "../ninitfeatures.h" + +#ifndef ERRMSG_PUTS_LEN +#define ERRMSG_PUTS_LEN 15 +#endif + +void errmsg_put(int fd, const char *buf, unsigned int len) /*EXTRACT_INCL*/ { + static struct iovec errmsg_iov[ERRMSG_PUTS_LEN]; + static int k; + if (buf==0 || k==ERRMSG_PUTS_LEN) { + if (fd>=0) writev(fd,errmsg_iov,k); + k = 0; + } + if (buf && len) { + errmsg_iov[k].iov_base = (char *)buf; + errmsg_iov[k].iov_len = len; + k++; + } +} diff --git a/lib/errmsg_puts.c b/lib/errmsg_puts.c new file mode 100644 index 0000000..41c3b88 --- /dev/null +++ b/lib/errmsg_puts.c @@ -0,0 +1,5 @@ +#include "../ninitfeatures.h" +void errmsg_puts(int fd, const char *buf) /*EXTRACT_INCL*/ { + if (buf==0) { errmsg_put(fd, buf, 0); return; } + if (buf[0]) errmsg_put(fd, buf, str_len(buf)); +} diff --git a/lib/error_string.c b/lib/error_string.c new file mode 100644 index 0000000..d7fd210 --- /dev/null +++ b/lib/error_string.c @@ -0,0 +1,16 @@ +#include "../ninitfeatures.h" +#if 0 +struct error_table { int n; char *s; }; /*EXTRACT_UNMOD*/ +#endif + +char *error_string(struct error_table *table, int n) /*EXTRACT_INCL*/ { + static char y[28]; + char *x=y; + for (; table->s; table++) + if (table->n == n) return table->s; + + x += str_copy(x,"error="); + x += fmt_ulong(x,n); + *x = 0; + return y; +} diff --git a/lib/fu.c b/lib/fu.c new file mode 100644 index 0000000..074007d --- /dev/null +++ b/lib/fu.c @@ -0,0 +1,16 @@ +#include "../int_defs.h" + +static char fu_buffer[7*12]; +/* format up to 6 numbers */ + +char *fu(uint32t u) /*EXTRACT_INCL*/ { + static char k=7; + char *p = fu_buffer + 12*k; + *--p = 0; + do { + *--p = '0' + (u%10); + u /= 10; + } while (u); + if (--k == 1) k=7; + return p; +} diff --git a/lib/nano_sleep.c b/lib/nano_sleep.c new file mode 100644 index 0000000..6da74a0 --- /dev/null +++ b/lib/nano_sleep.c @@ -0,0 +1,6 @@ +#include "../int_defs.h" +#include <time.h> +void nano_sleep(uint32t sec, uint32t nsec) /*EXTRACT_INCL*/ { + struct timespec ts = { sec, nsec }; + nanosleep(&ts, 0); +} diff --git a/lib/open_tmpfd.c b/lib/open_tmpfd.c new file mode 100644 index 0000000..e94bf32 --- /dev/null +++ b/lib/open_tmpfd.c @@ -0,0 +1,18 @@ +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include "../ninitfeatures.h" + +int open_tmpfd(char *target, char *tmp, int mode) /*EXTRACT_INCL*/ { + unsigned long len; + char *x; + int fd; + for (len=0 ;; len++) { + x = tmp + str_copy(tmp, target); + if (len) x += fmt_ulong(x,len); + x[0] = '~'; x[1] = 0; + fd = open(tmp, O_WRONLY|O_CREAT|O_EXCL, mode); + if (fd >=0 || errno != EEXIST) break; + } + return fd; +} diff --git a/lib/pathexec_run.c b/lib/pathexec_run.c new file mode 100644 index 0000000..2e369e1 --- /dev/null +++ b/lib/pathexec_run.c @@ -0,0 +1,43 @@ +/* again DJB; see http://cr.yp.to */ +#include <unistd.h> +#include <errno.h> +#include <alloca.h> +#include <stdlib.h> + +#include "../ninitfeatures.h" + +void pathexec_run(char *file,char **argv,char **envp) /*EXTRACT_INCL*/ { + char *path,*tmp; + int savederrno=0; + unsigned int len, next, file_len; + + if (file[str_chr(file,'/')]) { execve(file,argv,envp); return; } + file_len = str_len(file) + 1; + + path = env_get("PATH"); + if (!path) path = "/bin:/usr/bin"; + tmp = alloca(4 + str_len(path) + file_len); + if (!tmp) { errno=ENOMEM; return; } + + for (;;) { + next = str_chr(path,':'); + len = next; + + if (next==0) { tmp[0] = '.'; len = 1; } + else { byte_copy(tmp,next,path); } + tmp[len] = '/'; + byte_copy(tmp+len+1, file_len, file); + + execve(tmp,argv,envp); + if (errno != ENOENT) { + savederrno = errno; + if ((errno != EACCES) && (errno != ENOEXEC) && (errno != ENOTDIR)) return; + } + + if (path[next]==0) { + if (savederrno) errno = savederrno; + return; + } + path += (next+1); + } +} diff --git a/lib/read_header.c b/lib/read_header.c new file mode 100644 index 0000000..4a78b23 --- /dev/null +++ b/lib/read_header.c @@ -0,0 +1,18 @@ +#include <unistd.h> +#include <fcntl.h> + +#define MEM_BUF 160 + +char *read_header(const char *name) /*EXTRACT_INCL*/ { + static char buf[MEM_BUF+1]; + int fd, k; + + fd =open(name, O_RDONLY); + if (fd < 0) return 0; + k =read(fd, buf, MEM_BUF); + close (fd); + if (k < 0) return 0; + + buf[k] = 0; + return buf; +} diff --git a/lib/read_ulongs.c b/lib/read_ulongs.c new file mode 100644 index 0000000..90720ff --- /dev/null +++ b/lib/read_ulongs.c @@ -0,0 +1,8 @@ +#include "../ninitfeatures.h" + +int read_ulongs(char *name, unsigned long *u, int len) /*EXTRACT_INCL*/ { + char *x = read_header(name); + int dummy; + if (x==0) return 0; + return scan_ulongs(x, u, len, scan_ulong, ':', &dummy); +} diff --git a/lib/scan_sec.c b/lib/scan_sec.c new file mode 100644 index 0000000..6377399 --- /dev/null +++ b/lib/scan_sec.c @@ -0,0 +1,23 @@ +#include "../ninitfeatures.h" + +unsigned int scan_sec(const char *src, unsigned long *ul) /*EXTRACT_INCL*/ { + unsigned long tmp, u=0; + char ch, *s = (char *)src; + for (; *s; ) { + s += scan_ulong(s, &tmp); + ch = *s; + if (ch > 96) ch -= 32; /* upper case */ + + switch (ch) { + case 'W': tmp *= 10080; s++; break; + case 'D': tmp *= 1440; s++; break; + case 'H': tmp *= 60; s++; break; + case 0: break; + default: u += tmp; goto ready; + } + u += tmp; + } + ready: + *ul = u * 60; + return s-src; +} diff --git a/lib/scan_ulongs.c b/lib/scan_ulongs.c new file mode 100644 index 0000000..db5631f --- /dev/null +++ b/lib/scan_ulongs.c @@ -0,0 +1,17 @@ +#include "../ninitfeatures.h" + +unsigned int scan_ulongs(char *src, unsigned long *u, int len, unsigned int (*op)(), char sep, int *read_len) /*EXTRACT_INCL*/ { + int j, k; + char *p=src; + + for (k=0; k<len;) { + j = op(p, u+k); if (j==0) break; + ++k; + p += j; + if (*p != sep) break; + ++p; + } + + *read_len = (p-src); + return k; +} diff --git a/lib/skip_comments.c b/lib/skip_comments.c new file mode 100644 index 0000000..fd0bdde --- /dev/null +++ b/lib/skip_comments.c @@ -0,0 +1,11 @@ +void skip_comments(char **s) /*EXTRACT_INCL*/ { + char **d, *p; + for (d=s; (p=*s); s++) { + if (p[0] == '#') { + if (p[1] == '#') ++p; + else continue; + } + *d++ = p; + } + *d=0; +} diff --git a/lib/splitmem.c b/lib/splitmem.c new file mode 100644 index 0000000..f5d13aa --- /dev/null +++ b/lib/splitmem.c @@ -0,0 +1,18 @@ +unsigned int splitmem(char **v, char *s, char c) /*EXTRACT_INCL*/ { + if (v) { + char **w=v; + *w++=s; + for (;;) { + while (*s && *s!=c) s++; + if (*s==0) break; + *s=0; + *w++ = ++s; + } + *w=0; + return (w-v); + } else { + unsigned int n=1; + for (; *s; s++) if (*s==c) n++; + return n; + } +} diff --git a/lib/strpbrk.c b/lib/strpbrk.c new file mode 100644 index 0000000..9f39fc3 --- /dev/null +++ b/lib/strpbrk.c @@ -0,0 +1,10 @@ +#include "../ninitfeatures.h" + +char *strpbrk(const char *s, const char *accept) /*EXTRACT_INCL*/ { + register int i,l=str_len(accept); + for (; *s; s++) + for (i=0; i<l; i++) + if (*s == accept[i]) + return (char*)s; + return 0; +} diff --git a/lib/strstr.c b/lib/strstr.c new file mode 100644 index 0000000..39e30e5 --- /dev/null +++ b/lib/strstr.c @@ -0,0 +1,16 @@ +#include "../ninitfeatures.h" + +char *strstr(const char *haystack, const char *needle) /*EXTRACT_INCL*/ { + unsigned int nl=str_len(needle); + unsigned int hl=str_len(haystack); + int i; + if (!nl) goto found; + + for (i=hl-nl+1; i>0; --i) { + if (*haystack==*needle && !byte_diff(haystack,nl,needle)) +found: + return (char*)haystack; + ++haystack; + } + return 0; +} diff --git a/lib/utmp_io.c b/lib/utmp_io.c new file mode 100644 index 0000000..1d8c423 --- /dev/null +++ b/lib/utmp_io.c @@ -0,0 +1,29 @@ +#include <unistd.h> +#include <fcntl.h> +#include <utmp.h> + +#define UTMP_SIZE (sizeof(struct utmp)) + +/* type: F_RDLCK or F_WRLCK */ +struct utmp *utmp_io(int fd, struct utmp *ut, int type) /*EXTRACT_INCL*/ { + int ret; + struct flock fl; + int (*op)() = (type==F_WRLCK) ? (int(*)())write : (int(*)())read; + + fl.l_whence = SEEK_CUR; + fl.l_start = 0; + fl.l_len = UTMP_SIZE; + fl.l_pid = 0; + fl.l_type = type; + + if (fcntl(fd, F_SETLKW, &fl)) return 0; + ret = op(fd, ut, UTMP_SIZE); + + fl.l_start = -UTMP_SIZE; + fl.l_type = F_UNLCK; + + fcntl(fd, F_SETLK, &fl); + + if (ret != UTMP_SIZE) return 0; + return ut; +} diff --git a/lib/x_atoi.c b/lib/x_atoi.c new file mode 100644 index 0000000..2f6a5fb --- /dev/null +++ b/lib/x_atoi.c @@ -0,0 +1,12 @@ + +int x_atoi(const char *src) /*EXTRACT_INCL*/ { + register const char *s; + register long int dest=0; + register unsigned char c; + + s=src; + if (*s=='-' /* || *s=='+' */) ++s; + + while ((c=*s-'0')<10) { ++s; dest=dest*10 + c; } + return (*src=='-') ? -dest : dest; +} diff --git a/library_files b/library_files new file mode 100644 index 0000000..f30c96f --- /dev/null +++ b/library_files @@ -0,0 +1,52 @@ +Z/byte_copy.o +Z/byte_copyr.o +Z/byte_diff.o +Z/byte_set.o +Z/byte_zero.o +Z/str_chr.o +Z/str_copy.o +Z/str_copyn.o +Z/str_diff.o +Z/str_diffn.o +Z/str_len.o +Z/str_rchr.o +Z/atoulong.o +cron.o +djb/buffer_get.o +djb/buffer_put.o +djb/buffer_putc.o +djb/buffer_puts.o +djb/env_get.o +djb/fmt_ulong.o +djb/scan_8ulong.o +djb/scan_ulong.o +lib/do_wtmp.o +lib/err.o +lib/err_b.o +lib/errmsg_argv0.o +lib/errmsg_put.o +lib/errmsg_puts.o +lib/error_string.o +lib/fu.o +lib/nano_sleep.o +lib/open_tmpfd.o +lib/pathexec_run.o +lib/read_header.o +lib/read_ulongs.o +lib/scan_sec.o +lib/scan_ulongs.o +lib/skip_comments.o +lib/splitmem.o +lib/strpbrk.o +lib/strstr.o +lib/utmp_io.o +lib/x_atoi.o +misc/child_block.o +misc/dup2_inout.o +misc/fmt_argv.o +misc/opendevconsole.o +misc/set_sigaction.o +misc/sulogin.o +misc/system_child_block.o +misc/system_set_sigaction.o +softlimit.o diff --git a/man/bootlog.8 b/man/bootlog.8 new file mode 100644 index 0000000..f963e29 --- /dev/null +++ b/man/bootlog.8 @@ -0,0 +1,89 @@ +.TH bootlog 8 "Dec 28, 2009" +.SH NAME +bootlog \- write stdout/stderr of a program to file +.SH SYNOPSIS +.B bootlog +[-12ctar] logsize logfile program [arguments] + +.SH DESCRIPTION +.B bootlog +is used to start a program and write stdout/stderr to a disk file. +This works also before mouning any file systems. + +.B bottlog +is designed to log the output of scripts/services at boot time, +before mounting any file system. This is typical for +system init. + +.B bootlog +expects that when the program exits, the +.I logfile +is writable! + +.SH OPTIONS +.TP +\-1 +log only stdout +.TP +\-2 +log only stderr; default is to log stdout and stderr +.TP +\-c +create logfile +.TP +\-t +truncate logfile +.TP +\-a +append to logfile +.TP +\-r +replace old +.I logfile +with +.I logfile~ +.TP +.I logsize +maximal size of output to be logged +.TP +.I logfile +disk file name +.TP +.I program +the name of the +.I program +to start +.TP +.I arguments +additional arguments for +.I program + +.SH WARNING +Use the option \-c to force creating of the +.I logfile. + +Actually the options \-c, \-a, \-t add O_CREAT, O_APPEND, O_TRUNC +flags to open(2) for +.I logfile + +.SH EXAMPLE +bootlog -ctr 120000 /tmp/.sysinit.log /etc/rc.d/rc.sysinit + +You will have the files +.I /tmp/.sysinit.log +and +.I /tmp/.sysinit.log~ + +.SH ENVIRON +.B bootlog +uses the variable PATH to start +.I program +.br +If PATH is undefined it uses PATH=/bin:/usr/bin + +.SH AUTHOR +.B bootlog +is part of ninit package written by Nikola Vladov + +.SH "SEE ALSO" +ninit(8), open(2) diff --git a/man/inittab.8 b/man/inittab.8 new file mode 100644 index 0000000..bcede1c --- /dev/null +++ b/man/inittab.8 @@ -0,0 +1,98 @@ +.TH ninit\-inittab 8 "Dec 28, 2009" +.SH NAME +ninit\-inittab \- convert /etc/inittab to service directory +.SH SYNOPSIS +.B ninit\-inittab +.I inittab_file +.I home_directory +.I output_script + +.SH DESCRIPTION +.B ninit\-inittab +creates a script using +.I /etc/inittab +file. +This script can be used to create a service directory easy. + +.SH OPTIONS +.TP +.I inittab_file +input source file +.TP +.I home_directory +home directory for +.B ninit +.TP +.I output_script +name of the output script + +.SH USAGE +.B Case A. +If you don't have services in +.I /etc/ninit +you can start: + +.PP +.RS +cd /tmp +.br +ninit\-inittab +/etc/inittab /etc/ninit services.sh +.br +less services.sh +.br +/tmp/services.sh +.RE +.PP + +Then check what the script has done in +.I /etc/ninit + +.B Case B. +If you already have a +.I /etc/ninit +directory with services, +and don't want to make any changes there you can type: + +.PP +.RS +cd /tmp; cp /etc/inittab /tmp; vi inittab +.br +ninit\-inittab +/tmp/inittab /tmp/srv services.sh +.br +less services.sh +.br +/tmp/services.sh +.RE +.PP + +Then check what the script has done in +.I /tmp/srv. +If you find something +interesting there you can copy it to +.I /etc/ninit + +.SH AUTHOR +.B ninit\-inittab +was written by Nikola Vladov. + +The aim was to easily convert a host running +SysVinit to ninit. In my opinion creating services is very easy. +Maybe you have to look +in some already prepared service directory first. + +Ask google for "ninit archlinux" and you will find +an excellent git repository with services for +.I /etc/ninit + + +.SH FILES +.I /etc/inittab +.br +.I /etc/ninit/ + +.SH "SEE ALSO" +ninit(8), ninit\-runlevel(8), ninit\-sysvinit(8), pututmpid(8) +.br +init(8), inittab(5), runlevel(8) diff --git a/man/ninit.8 b/man/ninit.8 new file mode 100644 index 0000000..e6a9e8a --- /dev/null +++ b/man/ninit.8 @@ -0,0 +1,178 @@ +.TH ninit 8 "Jan 15, 2010" +.SH NAME +ninit \- a UNIX process no 1 +.SH SYNOPSIS +.B ninit +[\-Mnumber] [\-Hhome] [\-Ssystem] [service] ... + +.SH DESCRIPTION +.B ninit +is a possible first process the kernel starts. It can +start/stop/monitor all services the OS needs. + +To use ninit as system init, first read available documentation in +.I http://riemann.fmi.uni-sofia.bg/ninit/ +and then add the parameter +\fIinit=/sbin/ninit\fR +to your kernel command line. + +If you want to use ninit +only to start/monitor services and continue to use +the default init(8) then put in +.I /etc/inittab +.br +.B NI:12345:respawn:/sbin/ninit +.br +In this case you should remove the service +.B sysvinit +and don't use the programs: +ninit\-runlevel(8), ninit\-sysvinit(8). +Similarly it is possible to start ninit using +.B /etc/init.d/ninit +script. + + +.SH USAGE +.B ninit +will by default do nothing except start the ninit +service defined in +.I /etc/ninit/default +which usually contains a file named +.I depends +specifying which services are to be started at bootup. + +To control ninit use the companion program +.B nsvc. +Do not make it SUID unless you know what are you doing! + +The program +.B ninit\-sysvinit +listens to the fifo +.I /dev/initctl +and allows SysVinit programs +shutdown, halt, reboot, telinit to work properly. +If there is a service +.I /etc/ninit/sysvinit +it starts +.B ninit\-sysvinit. + + +To stop the box running +.B ninit +use the programs +.B ninit\-shutdown +or +.B nsvc. + +.SH "NONROOT USAGE" +Any nonroot user can use +.B /sbin/ninit +to start/monitor own services. First make private +ninit directory with +.br +.B /etc/ninit/bin/ninit\-conf ~/.ninit +.br +and put somewhere in shell profile: +.B export NINIT_HOME=~/.ninit + +Then create some services in $NINIT_HOME and start +.br +.B /sbin/ninit -H$NINIT_HOME + +.SH OPTIONS +.TP +.B \-Mnumber +Tells ninit to use +.B number +bytes for memory buffer. One service uses approximately 30 bytes. +.TP +.B \-Hhome +Changes the ninit home. Default: +.I /etc/ninit +.TP +.B \-Ssystem +Changes the ninit system directory. Default: +.I sys + +.SH SIGNALS +On receiving of some signals +.B ninit +starts appropiate service. + +.TP +.B SIGINT +Normally the kernel sends this signal to ninit when CTRL-ALT-DEL is +pressed. It activates the \fIctrlaltdel\fP action and ninit +starts the service +.I ctrlaltdel +.TP +.B SIGWINCH +The kernel sends this signal when the \fIKeyboardSignal\fP key is hit. +It activates the \fIkbrequest\fP action +and ninit starts the service +.I kbreq +.TP +.B SIGHUP +Has the same effect as telinit q. +Ninit restarts the service +.I levelQ +.TP +.B SIGUSR1 +On receipt of this signal, ninit closes and re-opens its control fifo, +.I /dev/initctl. +Useful for bootscripts when /dev is remounted. +.TP +.B SIGPWR +Ninit starts the service +.I powerS. +This service starts the program +.B ninit-sysvinit +with one argument: powerS. + +.SH SERVICES +Each service has own subdirectory in +.I /etc/ninit/ +three. There are lots of config files for a service. +The main daemon +.B ninit +check only the files +.I depends, sync, respawn, end +to start a service. +Check olso the link: +.br +.I http://riemann.fmi.uni-sofia.bg/ninit/files.html + +If the servive name start with '#' or '\-' it is blacklisted. +You can now blacklist services temporarily by passing it on +the kernel command line. The first time they are to be started +will then be skipped. Use this, for example, to not start the dhcp +client when your notebook is not plugged in a network. +Look in ninitfeatures.h if ninit is compiled to use this option. + +.SH FILES +.I NINIT_HOME/in +.br +.I NINIT_HOME/out +.br +.I NINIT_HOME/sys/ +.br +.I /dev/initctl + + +.SH AUTHOR +ninit was written by Nikola Vladov and can be downloaded from +.I http://riemann.fmi.uni-sofia.bg/ninit/ + +.SH SEE ALSO +nsvc(8), ninit-service(8), ninit-reload(8) +.br +ninit-shutdown(8), ninit-reboot(8), nkillall(8) +.br +ninit-sysvinit(8), ninit-runlevel(8) +.br +minit(8), +.I http://www.fefe.de/minit/ +.br +init(8), shutdown(8), halt(8), reboot(8) + +Part of this manpage was written by Erich Schubert. diff --git a/man/nkillall.8 b/man/nkillall.8 new file mode 100644 index 0000000..6564834 --- /dev/null +++ b/man/nkillall.8 @@ -0,0 +1,139 @@ +.TH nkillall 8 "Dec 28, 2009" +.SH NAME +nkillall \- send signals to all processes; write messages to users +.SH SYNOPSIS +.B nkillall +-[vq] [-s secs] [-M|W mesg] [-signum] [-E prog [arg[s]] +.SH DESCRIPTION +.B nkillall +sends signals +to all processes skipping it's own PID. +It is a simple program that does not use \fI/proc\fR FS. +It uses kill(2) and execve(2) syscalls. It is designed as +a replacement of the SysVinit killall5(8) command. + +.SH USAGE +It is not allowed to use +.B \-h +(signal SIGHUP) as first option! If you really want this then start: +.B nkillall +\-s0 \-hup ... + +.TP +.B \-v +verbose mode; \-vv means more verbose +.TP +.B \-q +quiet mode; ignores SIGINT signal; Ctrl-C does't work! +.TP +.B \-s +\fIsecs\fR +.br +sleep \fIsecs\fR +.TP +.B \-M +\fImesg\fR +.br +write \fImesg\fR to stdout. The message can include escape +symbols: +\\NNN, \\a, \\b, \\e, \\c, \\f, \\n, \\r, \\t, \\v, \\\\ +like in C language. Last message can be written again with +\-M% or \-W%. Example: + +.B nkillall +\-M'\\n\\aPlease logout! The system is going down...' \\ + \-W% \-s2 -W% \-s4 \-W% \-s12 \\ + \-M'\\tSending TERM signal' \-term ... +.TP +.B \-W +\fImesg\fR +.br +write \fImesg\fR to all logged users. The syntax is the same as \-M. +.B nkillall +determines logged users by looking at +.I /var/run/utmp. + +.br +In my opinion +.I /var/run/utmp +is unreliable! +Other programs like who(1), wall(1), login(1) also use this file. +If you feel that yours is insecure, better don't use the \-W option. + +.TP +.B \-signum +send all processes the singal \fIsignum\fR. +Some important signals can be encodded. For example SIGTERM can be typed with +\-15 or \-term. +Only the first letter is important! +The command +.B kill \-l +lists the signal numbers. +.TP +.B \-E +.I /path/to/program [arg[s]] +.br +execve(2) the program with some arguments. +This option must be last! The program will have the same PID as +.B nkillall. + +.SH NOTE +The options are applied immediately. Their position is important. +The next two examples work differently: + +nkillall \-q -s2 \-M'sending signal SIGTERM' \-15 ... +.br +nkillall \-s2 \-M'sending signal SIGTERM' \-15 \-q ... + +Use the options \-v[v] \-q after +.B nkillall +immediately. + +.SH WARNING +.B nkillall +also kills the script in which it is included. +Use it in scripts like: + +#!/bin/sh +.br +before commands +.br +exec nkillall [options] \-E/path/to/prog prog_opt(s) + +An example of wrong usage is the following: + +#!/bin/sh +.br +before commands +.br +nkillall ... +.br +after commands + +.SH EXAMPLES +.B nkillall +\-M'Sending all processes SIGTERM ...' \-s2 \-15 \\ +.br + \-M'Sending all processes SIGKILL ...' \-s6 \-9 \\ +.br + \-s1 \-E /path/to/program arg1 arg2 ... + +.B nkillall +\-v \-s1 \-15 \-cont \-s6 \-kill \-s1 \-E/path/to/prog arg(s) ... + +.B nkillall +\-vv \-pause \-s59 \-continue \-M'Hello world!' + +.SH FILES +.I /var/run/utmp + +.SH AUTHOR +.B nkillall +is included in ninit package and can be downloaded from +.br +.I http://riemann.frmi.uni-sofia.bg/ninit/ + +.SH "SEE ALSO" +ninit(8), kill(1), kill(2), execve(2), utmp(5) +.br +init(8), killall5(8) diff --git a/man/nsvc.8 b/man/nsvc.8 new file mode 100644 index 0000000..3ac0900 --- /dev/null +++ b/man/nsvc.8 @@ -0,0 +1,240 @@ +.TH nsvc 8 "Jan 19, 2010" +.SH NAME +nsvc \- control ninit +.SH SYNOPSIS +.B nsvc +[ -Sservice ] +[ +.B \-[uodgpchaitkorRDCLHVWZE] +] +.I service +[\fI...\fR] +.br +.B nsvc -Ppid +.I service +. +.SH DESCRIPTION +.B nsvc +is the management interface to ninit. +.I service +is the service directory name relative to /etc/ninit. +You can also include /etc/ninit/ in the service name. +.PP +Each service directory contains control files. +They are described on +.I http://riemann.fmi.uni-sofia.bg/ninit/ + +.PP +It is possible to make nsvc SUID. +.PP +.RS +.B chown root.root /bin/nsvc +.br +.B chmod 4711 /bin/nsvc +.RE +.PP +Then nsvc opens the pipes +.IR /etc/ninit/in , +.I /etc/ninit/out +and switches to real UID. +If UID is nonzero only limited set of operation are allowed. +. +.SH OPTIONS +If no options are given, +.B nsvc +will just print a diagnostic message to stdout, saying if the +service is up, down or finished, which PID it has if it is up, and for +how long it has been in this state. + +Only the service name +.B ALL +means all services. + +.TP +.B \-Sservice +Skip service. Apply this option immediately after +.B nsvc. +Don't insert space between S and service. +Examples: +.br +.B nsvc +\-Sngetty \-Ssshd \-Slogger \-d ALL +.br +.B nsvc +\-Sngetty \-W3 ALL || +.B nsvc +\-Sngetty \-k ALL + +.TP +.B \-u \-uNumber +Up. +If the service is not running, start it. +If the service stops, restart it. If +.B Number +is nonzero and the service is down start it after +.B Number +seconds. +.TP +.B \-o \-oNumber +Once. +If the service is down, start it. +If the service stops, do not restart it. +If +.B Number +is nonzero and the service is down, start it after +.B Number +seconds; if it is up, restart it later. +.TP +.B \-d +Down. +If the service is running, send it a TERM signal and then a CONT signal. +After it stops, do not restart it. +.TP +.B \-r +Stop respawn. +Set respawn flag to OFF. This does not start/stop the service. +.TP +.B \-R +Start respawn. +Set respawn flag to ON. This does not start/stop the service. +.TP +.B \-p +Pause. +Send the service a STOP signal. +.TP +.B \-c +Continue. +Send the service a CONT signal. +.TP +.B \-h +Hangup. +Send the service a HUP signal. +.TP +.B \-a +Alarm. +Send the service an ALRM signal. +.TP +.B \-i +Interrupt. +Send the service an INT signal. +.TP +.B \-t +Terminate. +Send the service a TERM signal. +.TP +.B \-k +Terminate. +Send the service a KILL signal. +.TP +.B \-g +Get. Output just the PID. +.TP +.B \-Ppid \fIservice\fR +Set pid of service. +.TP +.B \-D \fIservice\fR +Print dependencies. +This will print all the names of all the services that were started +because this services depended on them. Example: +.br +.B nsvc -D default +.TP +.B \-D +Print ninit memory usage statistics. +.TP +.B \-H +Print history. +This will print the names of some recently spawned processes. +This is useful if you see a process looping (initialization fails and +ninit is restarting it all the time). +.TP +.B \-L +Print all services loaded in memory. +.TP +.B \-V +Print version +.TP +.B \-Wnumber +Wait at most +.B number +seconds service(s) to finish. Example: +.br +.B nsvc \-d qmail +.br +.B nsvc \-W180 qmail || nsvc -k qmail +.TP +.B \-Cnumber \-C+number +Tell ninit that the service is in CRON mode. +If +.B number +is zero it disables CRON mode. Let now=`date +%s`. +If +.B number < now +then ninit starts the service immediately, +otherwise ninit will start it latter. +The flag +.B \-C+number +(if the +.B number +is positive) +is equaivalent to the following: +.br +.B t=`expr now + number` +.br +.B nsvc -C$t ... + +To stop foo, +which is in CRON mode do: +.br +.B nsvc -C0 foo +.br +.B nsvc -d foo +.br +.\" To see the next CRON timestamp of foo type: +.\" .B nsvc foo +.TP +.B \-Z \-Znumber +Zero (free) a service. This is done with the ninit-reload program. +Example: +.br +.B nsvc -Z30 foo +.br +This removes foo (if such a service exists) +and prepares ninit to accept 30 new services approximately. +.TP +.B \-E \-Enumber +Update ninit environ. This is done by ninit-reload program. +Example: +.br +.B nsvc \-E36 ABC=12 UVW +.br +This updates the variable +.B ABC +and removes +.B UVW. +It prepares ninit to accept 36 new services approximately. +See the environ with: +.br +.B tr '\\\\000' '\\\\012' < /proc/1/environ + +. +.SH "RETURN CODES" +Generally, +.B nsvc +returns zero if everything is OK or 1 on error (could not +open /etc/ninit/in or /etc/ninit/out or there is no process with the +given name). In diagnostic mode, it will exit 0 if the service is up, 2 +if it is down or 3 if it is finished. + +. +.SH "ENVIRON" +.B nsvc +uses the variables +.B NINIT_MEMORY +and +.B NINIT_HOME. + +.SH "SEE ALSO" +ninit(8), ninit-scan(8) +.br +ninit-shutdown(8), nkillall(8), svc(8), msvc(8) diff --git a/man/pidfile.8 b/man/pidfile.8 new file mode 100644 index 0000000..97efe18 --- /dev/null +++ b/man/pidfile.8 @@ -0,0 +1,75 @@ +.TH ninit\-pidfile 8 "Dec 28, 2009" +.SH NAME +ninit\-pidfile \- work around daemons that always fork +.SH SYNOPSIS +.B ninit\-pidfile +.I servicename +.I pidfile +[ +.I -H home +] +.I command +.I [parameters] + +.SH DESCRIPTION +.B ninit\-pidfile +is used to work around daemons that insist on forking into the background, +but that do write a correct pid file. + +.B ninit\-pidfile +forks the actual service, then waits for the pidfile to +be written. Once it can read the pid from the pidfile it will tell +ninit the real pid and quit. + +.SH OPTIONS +.TP +.I servicename +the name of the service +ninit\-pidfile is installed for +.TP +.I pidfile +the filename to read the pid from +.TP +.I command +the real command to start +.TP +.I parameters +additional parameters for the command +.TP +.B \-H \fIhome\fR +.br +the home of ninit. Default: /etc/ninit + +.SH USAGE +With +.B ninit +you can prepare a service and if it forks and writes +the PID in some file then type in the service directory: + + echo /path/to/deamon.pidfile > +.I pidfile + +For apache this looks like: + + cd /etc/ninit/apache +.br + echo /var/run/apache.pid > +.I pidfile + +Don't use hard or soft links here! +.br +Then +.B ninit +will start apache using +.B ninit\-pidfile + +.SH AUTHOR +.B pidfilehack +was written +by Felix von Leitner. + +This manpage was written by Erich Schubert <[email protected]> +for the Debian GNU/Linux operating system. + +.SH "SEE ALSO" +ninit(8), nsvc(8), pidfilehack(8) diff --git a/man/pututmpid.8 b/man/pututmpid.8 new file mode 100644 index 0000000..7bcac33 --- /dev/null +++ b/man/pututmpid.8 @@ -0,0 +1,73 @@ +.TH pututmpid 8 "Dec 28, 2009" +.SH NAME +pututmpid \- write utmp/wtmp records and exec command +.SH SYNOPSIS +.B putupmpid +.I [-w] +.I ut_id +.I command +.I [parameters] +.br +.B pututmpid +.I reboot +.br +.B pututmpid +.I halt + + +.SH DESCRIPTION +.B pututmpid +is used to write records in utmp/wtmp files for running +getty/agetty/fgetty. +pututmpid writes the record and then execve()s a command. +The commands +.B login +and +.B getty +use the records written from pututmpid. + +After reboot it is possible to set +.B pututmpid reboot +in init scripts. +This will update /var/run/utmp with BOOT_TIME record. This +must be done after /var/run/utmp is writable. The usage of +.B pututmpid halt +is similar. It sets wtmp record (in /var/log/wtmp file). + +.SH OPTIONS +usually pututmpid is symlinked as \fIrun\fR command of a service. +.TP +.B \-w +debug mode -- write more info in /var/log/wtmp +.TP +.B ut_id +string at most 4 bytes long. examples: tty1,tty2, vc1,vc2,vc3... +Use different names for each virtual console! +.TP +.B command +the real command to start +.TP +.B parameters +additional parameters for the command + +.SH EXAMPLE +A typical use of this command will look like this: +.TP +/etc/ninit/getty/2 +.TP +/etc/ninit/getty/2/params +tty2 +.br +/sbin/fgetty +.br +tty2 +.TP +/etc/ninit/getty/2/run +-> /sbin/pututmpid + +.SH "SEE ALSO" +ninit(8), ninit\-runlevel(8) +.br +getty(8), {n|f|a|min}getty(8), +.br +login(1), utmp(5), runlevel(8) diff --git a/man/reboot.8 b/man/reboot.8 new file mode 100644 index 0000000..c1ef01b --- /dev/null +++ b/man/reboot.8 @@ -0,0 +1,59 @@ +.TH ninit\-reboot 8 "Dec 28, 2009" +.SH NAME +ninit-reboot \- reboot your system immediately +.SH SYNOPSIS +.B ninit\-reboot +.I RESTART +.br +.B niniy\-reboot +.I HALT +.br +.B ninit\-reboot +.I POWER_OFF +.br +.B ninit\-reboot +.I ENABLE_CAD +.br +.B ninit\-reboot +.I DISABLE_CAD + +.SH DESCRIPTION +.B ninit\-reboot +is used to reboot your system. + +It will not shut down services, unmount filesystems or notify +your users, but expects that this has already been done when it +is called. + +.SH USAGE + +To prevent accidential use of this application the parameters have to +be written in uppercase letters. +.TP 10 +.I RESTART +restart (reboot) the system +.TP +.I HALT +halt the kernel +.TP +.I POWER_OFF +power off the system if possible (supported by hardware) +.TP +.I ENABLE_CAD +halt the system. Enable CTRL\-ALT\-DEL key to restart the system +after halt. +.TP +.I DISABLE_CAD +halt the system. Disable CTRL\-ALT\-DEL key to restart the system +after halt. + + + +.SH AUTHOR +ninit\-reboot was contributed by Tommi Virtanen. + +This manpage was partially written by Erich Schubert <[email protected]> +for the Debian GNU/Linux operating system. + +.SH "SEE ALSO" +ninit(8), nsvc(8), ninit\-shutdown(8), nkillall(8) diff --git a/man/reload.8 b/man/reload.8 new file mode 100644 index 0000000..c8ac521 --- /dev/null +++ b/man/reload.8 @@ -0,0 +1,120 @@ +.TH ninit-reload 8 "Dec 28, 2009" +.SH NAME +ninit\-relaod \- replace running ninit with a new version +.SH SYNOPSIS +.B ninit\-reload +[options] [/path/to/ninit] [ninit_options] + +.SH DESCRIPTION +.B ninit\-reload +is used to replace a running ninit with a new version. + +It tries to retrieve the state information about running services from +ninit, then have ninit replace itself with the new version and +restore the stored state information. + +.SH OPTIONS +Unless the \-u option is given, ninit\-reload assumes you are running +in test mode. +.TP +\-v +verbose operation +.TP +\-u +update mode +.TP +\-m +dump ninit memory buffer to stdout +.TP +\-d +dump services data to stdout +.TP +\-R +.I service +.br +remove +.I service +from active list +.TP +\-r +.I number +.br +remove +service with +.I number +from active list. Example: +.RS + ninit\-reload -v /sbin/ninit +.br + ninit\-reload -v -r 3 -R qmail -u /sbin/ninit +.RE +.TP +\-e +.I string +.br +update ninit environ. Example: +.br +.B ninit\-reload -v -e ABC=12 -e UVW -u /sbin/ninit +.br +This updates the variable +.B ABC +and removes +.B UVW. +See the environ after that with: +.B tr '\\\\000' '\\\\012' < /proc/1/environ +.TP +\-E +.I file +.br +update ninit environ using +.I file. +The syntax for +.I file +is the same as in the file +.I environ +for services. +.TP +\-a +.I number +.br +reload ninit and calculate memory buffer to +.I number +additional services. Check the result with: +.B ps axww. +.TP +\-t +.I time_diff +.br +add +.I time_diff +seconds to each service. Useful if you change the time with hwclock. +.I time_diff +can also be a negative number. +.TP +\-f +.I data_file +.br +don't retrieve services from ninit. Use this file instead. +For example you can start: +.PP +.RS + ninit-reload -d > /tmp/ninit.data +.br + ninit-reload -v -u -f /tmp/ninit.data /sbin/ninit +.RE +.PP + +.SH "ENVIRON" +.B ninit\-reload +uses the variables +.B NINIT_MEMORY +and +.B NINIT_HOME. + + +.SH AUTHOR +This manpage was partially written by Erich Schubert <[email protected]> +for the Debian GNU/Linux operating system. + +.SH "SEE ALSO" +ninit(8), nsvc(8) diff --git a/man/runlevel.8 b/man/runlevel.8 new file mode 100644 index 0000000..bdb05a6 --- /dev/null +++ b/man/runlevel.8 @@ -0,0 +1,108 @@ +.TH ninit-runlevel 8 "Jan 16, 2010" +.SH NAME +ninit-runlevel +\- set runlevels for compatibility with SysVinit +.SH SYNOPSIS +.B ninit-runlevel +.B LEVEL +[OPTION]... [-] [NAME=VALUE]... [PROGRAM [ARG]...] +.br +.B ninit-runlevel +. +.SH DESCRIPTION +.B ninit-runlevel +is a helper program to start service (script, program) with the same +environ as SysVinit. It also modifies the files +.I /var/run/utmp +and +.I /var/log/wtmp +writing runlevel records in them. +It is used mainly in ninit-inittab(8) output script. + +It sets the following variables: +INIT_VERSION=2.86, +CONSOLE=/dev/console, +RUNLEVEL, +PREVLEVEL, +PATH=/bin:/usr/bin:/sbin:/usr/sbin. +The variable NINIT_RUNLEVEL always has the same value +as RUNLEVEL. +The program does not modify or reset the variable INIT_HALT. + +.SH OPTIONS +Actually +.B ninit\-runlevel +has the same syntax between +.B LEVEL +and +.B PROGRAM +as the command env(1). + +If +.B ninit-runlevel +is started as a service you can use +.I environ +file +to set some environment variables. +However in this case +.B ninit-runlevel +overwrites the variables: +INIT_VERSION, +CONSOLE, +RUNLEVEL, +PREVLEVEL, +PATH +and NINIT_RUNLEVEL. +You can reset some of them, for example PATH. +.TP +\-i +start with an empty environment +.br +a mere - implies -i +.TP +\-u +.I variable +.br +remove the +.I variable +from the environment + +.SH "EXAMPLES" +In the next examples we modify PATH, INIT_HALT and CONSOLE + +.B ninit-runlevel S +PATH=/sbin:/bin /etc/rc.d/rc.single +.br +.B ninit-runlevel 0 +INIT_HALT=POWERDOWN -u CONSOLE /etc/rc.d/rc.halt + +See the environ with (don't start it as root \- +the program will then modify +.I /var/run/utmp +) + +.B ninit-runlevel 5 +/usr/bin/env + +.SH WARNING +Don't remove the file +. I /var/run/utmp +if you want correct PREVLEVEL and RUNLEVEL variables. +.B ninit-runlevel +stores the info about levels there. +.B ninit +does not use the +.I /var/run/utmp +file, nor PREVLEVEL, RUNLEVEL, NINIT_RUNLEVEL. + +.SH "FILES" +.I /var/run/utmp +.br +.I /var/log/wtmp + +.SH "SEE ALSO" +utmp(5), env(1), runlevel(8) +.br +ninit(8), ninit\-sysvinit(8), ninit\-shutdown(8), ninit\-inittab(8) +.br +init(1), shutdown(8), reboot(8), halt(8) diff --git a/man/scan.8 b/man/scan.8 new file mode 100644 index 0000000..674a1f9 --- /dev/null +++ b/man/scan.8 @@ -0,0 +1,99 @@ +.TH ninit\-scan 8 "Jan 19, 2010" +.SH NAME +ninit\-scan \- scan directory and start/stop services +.SH SYNOPSIS +.B ninit\-scan +[ +.B \-[uod] +] +.I services_directory +.I ninit_home +. +.SH DESCRIPTION +.B ninit\-scan +scans a directory to start/stop a collection of services. + +Service definitions are installed, configured and activated as subdi- +rectories of the +.I services_directory. +As ninit\-scan sequentially scans the +.I services_directory, +it looks for subdirectory names not beginning with `.'. If +ninit\-scan then finds the `sticky' bit set on the subdirectory, +it considers the service definition ``active'' and +attempts to start/stop the corrsponding service. + + + +.SH OPTIONS +If no option is given +.B ninit\-scan +try to start the service in respawn ON or OFF mode +depending on the existence of the file +.B respawn +in the service subdirectory. + +.TP +.B \-u +Up. +If the service is not running, start it. +If the service stops, restart it. +.TP +.B \-o +Once. +If the service is down, start it. +If the service stops, do not restart it. +.TP +.B \-d +Down. +If the service is running, send it a TERM signal and then a CONT signal. +After it stops, do not restart it. + +.SH EXAMPLES + +.B ninit\-scan \-u net /etc/ninit +.br +start all services /etc/ninit/net/* which have `sticky' bit set +in respawn mode. + +.B ninit\-scan etc /etc/ninit +.br +start all services /etc/ninit/etc/* which have `sticky' bit +set. + +.B ninit\-scan \-d '' /etc/ninit +.br +stop all services /etc/ninit/* which have `sticky' bit set. + +.SH USAGE + +This is similar to the file +.I depends. +Put in +.I rsetup +the following: + +.B #!/bin/sh +.br +.B exec $2/bin/ninit\-scan $1 $2 + + +The program is shell script. See the code to understand how it works. +.B ninit\-scan +is designed to permit easy service activation/deactivation using +the chmod(1) utility. +You can set/unset `sticky' bit with + + +chmod +t myservice +.br +chmod \-t myservice + +.SH AUTHOR +Nikola Vladov. +Thanks to Wayne Marshall for the `sticky' bit idea. +.br +.I http://b0llix.net/perp/ + +.SH SEE ALSO +ninit(8), nsvc(8), perpd(8), chmod(1) diff --git a/man/service.8 b/man/service.8 new file mode 100644 index 0000000..75c3c33 --- /dev/null +++ b/man/service.8 @@ -0,0 +1,46 @@ +.TH ninit\-service 8 "Dec 28, 2009" +.SH NAME +ninit\-service \- print info about a service +.SH SYNOPSIS +.B ninit\-service +[-OPTIONS] service(s) +.br +.B ninit\-service +-E service file +. +.SH DESCRIPTION +.B ninit\-service +is a shell script which prints info about service(s). +It only looks in the service directory. +Use +.B nsvc +to obtain info about services loaded in ninit memory. + +.SH OPTIONS +.TP +\-A ascii output +.TP +\-C show end of lines; for cat +.TP +\-L print long lines; for ls +.TP +\-E +.I service file +.br +edit service/file; +default editor: /bin/vi; change it with: +.br +echo /usr/bin/emacs -nw > /etc/ninit/.editor +.TP +\-H/other/home +default home: /etc/ninit + +.SH EXAMPLE +.B ninit\-service +ngetty +.br +.B ninit\-service +`find /etc/ninit/ -type d` + +.SH "SEE ALSO" +ninit(8), nsvc(8), ngetty(8) diff --git a/man/shutdown.8 b/man/shutdown.8 new file mode 100644 index 0000000..62d6ccf --- /dev/null +++ b/man/shutdown.8 @@ -0,0 +1,89 @@ +.TH ninit-shutdown 8 "Dec 28, 2009" +.SH NAME +ninit-shutdown \- shutdown the ninit init system. +.SH SYNOPSIS +.B ninit-shutdown +\-[\fIrhoqvstmST\fR] [\-E /path/to/program [arg1 arg2 ...]] + +.SH DESCRIPTION +.B ninit-shutdown +tries to properly shutdown your system with ninit. + +.SH USAGE +.TP 9 +\-r +reboot after shutdown +.TP +\-h +halt after shutdown +.TP +\-o +power-off after shutdown (default) +.TP +\-q +quiet mode; ignores SIGINT signal; Ctrl-C does't work! +.TP +\-v +be verbose +.TP +\-m +only shutdown the ninit-part and exit +.TP +\-s \fIsecs\fR +starting delay +.TP +\-t \fIsecs\fR +delay between SIGTERM and SIGKILL +.TP +\-E \fIprog\fR +execute \fIprog\fR after KILLALL; must be the last option! +.TP +\-T \fIsecs\fR +if \fIsecs\fR is nonzero shutdown twice ninit part +.TP +\-S \fIabcd\fR +skip to shutdown the service \fIabcd\fR + +.SH NOTES +If the flags -m and -E are off then the program starts the service +.I halt +or +.I reboot +depending of the flags -h -o and -r respectively. + +If the flags -E and -m are on then +.B ninit-shutdown +execve(2)s the +\fIprog\fR after shutting down the ninit-part. + +If the flag -E is on and the flag -m is off then +.B ninit-shutdown +execve(2)s +the \fIprog\fR after sending SIGTERM and SIGKILL to all processes. + +.B ninit-shutdown +clears respawn/cron flags on all services +including those skipped with -S flag. + +. +.SH "ENVIRON" +.B ninit-shutdown +uses the variables +.B NINIT_MEMORY +and +.B NINIT_HOME. + +.SH AUTHOR +.B ninit +was written by Nikola Vladov and can be downloaded from +.br +.I http://riemann.frmi.uni-sofia.bg/ninit/ + +Parts of +.B ninit-shutdown +were contributed by Bernd Wachter. +.br +Parts of this manpage was written by Erich Schubert. + +.SH "SEE ALSO" +ninit(8), nsvc(8), execve(2), nkillall(8) diff --git a/man/sysvinit.8 b/man/sysvinit.8 new file mode 100644 index 0000000..46a0b77 --- /dev/null +++ b/man/sysvinit.8 @@ -0,0 +1,155 @@ +.TH ninit-sysvinit 8 "Dec 28, 2009" +.SH NAME +ninit-sysvinit \- SysVinit emulator listening on /dev/initctl +.SH SYNOPSIS +.B ninit-sysvinit +.br +.B ninit-sysvinit +powerS + +.SH DESCRIPTION +.B ninit +does not use the +.I /dev/initctl +fifo. As a result the SysVinit commands +telinit, reboot, halt, shutdown do not work. +Some of them need to write to +.I /dev/initctl +to work properly. + +.B ninit-sysvinit +is a SysVinit emulator which listens on +.I /dev/initctl +and starts some services if there is any activity on the fifo. + +.SH USAGE +Five seconds after starting all services +.B ninit +tries to start the sysvinit service. +If the last service exists then +.B ninit +opens and listens on +.I /dev/initctl. +.B Never include +the service sysvinit in +.I /etc/ninit/default +nor start it at boot time. + +.SH OPTIONS +.B ninit\-sysvinit +reads the control file +.I sysvinit\-timeout +in the service directory. +It must contain two numbers n1:n2. +If there is not +any activity on +.I /dev/initctrl +for more than n1 seconds +the program exits. +If the number n1 is zero +.B ninit\-sysvinit +wait forever. + +If needed, +.B ninit +can start +.B ninit\-sysvinit +later again. + +.SH RUNLEVELS +SysVinit has runlevels 0123456S. The command +.br +.B telinit S +.br +writes the request to +.I /dev/initctl +and +.B ninit\-sysvinit +starts the service +.I levelS. +It works similarly with telinit 5, telinit Q or telinit U. +Then +.B ninit\-sysvinit +starts the +.I level5, +.I levelQ +or +.I levelU +service if it exists. + +.SH "POWER ACTIONS" +.B ninit\-sysvinit +also starts the services +.I powerF, +.I powerO +or +.I powerL. +The letters come from F(AIL), O(K) or L(OW). +The program can obtain the power request from +.I /dev/initctl +or from a SIGPWR signal and the file +.I /etc/powerstatus. +See the manual page init(8) for more info. + +.SH SIGNALS +Don't send signal SIGPWR to +.B ninit\-sysvinit. +Manpage init(8) says: + + +Usage of SIGPWR and +.I /etc/powerstatus +is discouraged. Someone wanting to +interact with init should use the +.I /dev/initctl +control channel. + +If some program still needs to use signal SIGPWR +it must send it dirrectly to +.B ninit. + +.SH ENVIRON +SysVinit +.B shutdown +sets the variable +INIT_HALT=POWERDOWN +or +INIT_HALT=HALT +depending on the options +\-r \-h \-H \-P. You can (re)set this variable +using: + +.B nsvc -E INIT_HALT +.br +.B nsvc -E INIT_HALT=POWERDOWN + +.SH "AUTHOR" +If you don't plan to use SysvInit's shutdown, reboot, +halt or telninit commands, you can do: + +.B cd /etc/ninit +.br +.B mv sysvinit sysvinit_ +.br +.B ninit\-reload \-v \-u /sbin/ninit + +Why did I write this SysVinit +.B emulator? +This is a good question. +Ninit has the ninit-shutdown, nkillall and ninit-reboot programs. There +is no need to use SysVinit halt, reboot... to stop the box clean. +See the code of the emulator. Maybe you will find the answer there. + +Nikola Vladov + +.SH FILES +.I /dev/initctl +.br +.I /etc/powerstatus +.br +.I NINIT_HOME/sysvinit/sysvinit\-timeout + +.SH SEE ALSO +nsvc(8), ninit-shutdown(8), ninit-runlevel(8) +.br +init(8), shutdown(8), halt(8), reboot(8), telinit(8) diff --git a/misc/BIN b/misc/BIN new file mode 100644 index 0000000..6abcaf0 --- /dev/null +++ b/misc/BIN @@ -0,0 +1,48 @@ +v:1::::: +d:::755::: +d:::755:/etc:: +d:::755:/etc/ninit:: + +# d:::755:/etc/ninit/bin:: +# g:::755:/etc/ninit/bin/:: +# x:::::argv0:: +# x:::::env:: +# x:::::conditional-init:: +# x:::::sleeprun:: +# x:::::install-bin:: +# x:::::serdo:: +# x:::::ninit-huge:: +# x:::::ninit-mmap:: +# x:::::ninit-conf:scripts/conf: +# x:::::ninit-scan:scripts/scan: + +g:::600:/etc/ninit/:: +x:::644::.sync:Version: +x:::644::.nsvc_help:nsvc_help: +p:::::in: +p:::::out: + +d:::755:/bin:: +x:::755:/bin/:nsvc:: + +d:::755:/sbin:: +g:::755:/sbin/:: +x:::::ninit-reload:reload: +x:::::ninit-reboot:reboot: +x:::::ninit-pidfile:pidfile: +x:::::ninit-sysvinit:sysvinit: +x:::::ninit-runlevel:runlevel: +x:::::bootlog:: +x:::::pututmpid:: +x:::::nkillall:: +x:::::ninit-shutdown:shutdown: +c:::::ninit-inittab:inittab: +c:::::ninit-service:scripts/service: + +d:::755:/etc/ninit/sys:: +g:::755:/etc/ninit/sys/:: +x:::::run:: +x:::::run-wait:wait: +x:::::update:: +x:::::remove:: +x:::::procfs:: diff --git a/misc/ETC b/misc/ETC new file mode 100644 index 0000000..aa55bef --- /dev/null +++ b/misc/ETC @@ -0,0 +1,18 @@ +d:::755:/etc:: +d:::755:/etc/ninit:: + +g:::600:/etc/ninit/:: +x:::644::.sync:Version: +x:::644::.nsvc_help:nsvc_help: + +v:1::::: +p:::::in: +p:::::out: + +d:::755:/etc/ninit/sys:: +g:::755:/etc/ninit/sys/:: +x:::::run:: +x:::::run-wait:wait: +x:::::update:: +x:::::remove:: +x:::::procfs:: diff --git a/misc/HOME b/misc/HOME new file mode 100644 index 0000000..91b9944 --- /dev/null +++ b/misc/HOME @@ -0,0 +1,25 @@ +v:1::::: +d:::755::: + +g:::755::: +d::::/sys:: +d::::/default:: +d::::/env:: +d::::/sleep:: +d::::/sh:: +d::::/S:: + +g:::600:/:: +x:::644::.sync:Version: +x:::644::.nsvc_help:nsvc_help: +p:::::in: +p:::::out: + +c:::755:/env/:env:: + +g:::755:/sys/:: +x:::::run:: +c:::::run-wait:wait: +c:::::update:: +c:::::remove:: +c:::::procfs:: diff --git a/misc/MAN b/misc/MAN new file mode 100644 index 0000000..f91815d --- /dev/null +++ b/misc/MAN @@ -0,0 +1,19 @@ +v:1::::: +d:::755::: +d:::755:/man8:: + +g:::644:/man8/:: +x:::::ninit.8.gz:: +x:::::nsvc.8.gz:: +x:::::ninit-scan.8.gz:scan.8.gz: +x:::::bootlog.8.gz:: +x:::::nkillall.8.gz:: +x:::::pututmpid.8.gz:: +x:::::ninit-shutdown.8.gz:shutdown.8.gz: +x:::::ninit-runlevel.8.gz:runlevel.8.gz: +x:::::ninit-sysvinit.8.gz:sysvinit.8.gz: +x:::::ninit-pidfile.8.gz:pidfile.8.gz: +x:::::ninit-inittab.8.gz:inittab.8.gz: +x:::::ninit-service.8.gz:service.8.gz: +x:::::ninit-reload.8.gz:reload.8.gz: +x:::::ninit-reboot.8.gz:reboot.8.gz: diff --git a/misc/child_block.c b/misc/child_block.c new file mode 100644 index 0000000..284fb73 --- /dev/null +++ b/misc/child_block.c @@ -0,0 +1,9 @@ +#include <sys/types.h> +#include <signal.h> + +void child_block(int type) /*EXTRACT_INCL*/{ /* SIG_BLOCK, SIG_UNBLOCK */ + sigset_t mask; + sigemptyset(&mask); + sigaddset(&mask, SIGCHLD); + sigprocmask(type, &mask, 0); +} diff --git a/misc/dup2_inout.c b/misc/dup2_inout.c new file mode 100644 index 0000000..13132d8 --- /dev/null +++ b/misc/dup2_inout.c @@ -0,0 +1,13 @@ +#include <unistd.h> +#include <fcntl.h> + +void dup2_inout(char *file, int from, mode_t mode) /*EXTRACT_INCL*/ { + int to = open(file, mode); + if (to == from || to == -1) return; + while (1) { + dup2(to,from); + fcntl(from,F_SETFD,0); + if (from++ != 1) break; + } + close(to); +} diff --git a/misc/fmt_argv.c b/misc/fmt_argv.c new file mode 100644 index 0000000..a61f8db --- /dev/null +++ b/misc/fmt_argv.c @@ -0,0 +1,10 @@ +#include "../ninitfeatures.h" + +int fmt_argv(int fd, char **argv, const char *sep) /*EXTRACT_INCL*/ { + int len=0; + for (; argv[len]; len++) { + errmsg_puts(fd, argv[len]); + errmsg_puts(fd, (char *)sep); + } + return len; +} diff --git a/misc/initreq.c b/misc/initreq.c new file mode 100644 index 0000000..c0160f0 --- /dev/null +++ b/misc/initreq.c @@ -0,0 +1,31 @@ + +#include <stdio.h> +#include <unistd.h> +#include "../initreq.h" + +int main() { + struct init_request req; + while (1) { + if (read(0, &req, sizeof(req)) != (int)sizeof(req)) return 1; + + printf("magic:\t%x\n" "cmd:\t%d\n" "runlevel:\t%d=%c\n" + "sleeptime:\t%d\n" + "reserved:\t%s\n" + "exec_name:\t%s\n" + "host:\t%s\n" + "term_type:\t%s\n" + "tty_id:\t%s\n" + "gen_id:\t%s\n" + "\n", + req.magic, req.cmd, req.runlevel, req.runlevel, + req.sleeptime, + req.i.bsd.reserved, + req.i.bsd.exec_name, + req.i.bsd.host, + req.i.bsd.term_type, + req.i.bsd.tty_id, + req.i.bsd.gen_id + ); + } + return 0; +} diff --git a/misc/opendevconsole.c b/misc/opendevconsole.c new file mode 100644 index 0000000..3f92223 --- /dev/null +++ b/misc/opendevconsole.c @@ -0,0 +1,12 @@ +#include <fcntl.h> +#include <unistd.h> + +void opendevconsole() /*EXTRACT_INCL*/ { + int fd; + if ((fd=open("/dev/console",O_RDWR|O_NOCTTY))>=0) { + dup2(fd,0); + dup2(fd,1); + dup2(fd,2); + if (fd>2) close(fd); + } +} diff --git a/misc/set_sigaction.c b/misc/set_sigaction.c new file mode 100644 index 0000000..2b429a6 --- /dev/null +++ b/misc/set_sigaction.c @@ -0,0 +1,10 @@ +#include <signal.h> +extern void sighandler(int sig); + +void set_sigaction(int sig) /*EXTRACT_INCL*/{ + struct sigaction sa; + sigemptyset(&sa.sa_mask); + sa.sa_handler=sighandler; + sa.sa_flags=SA_RESTART | SA_NOCLDSTOP; + sigaction(sig, &sa, 0); +} diff --git a/misc/sulogin.c b/misc/sulogin.c new file mode 100644 index 0000000..6f0aa26 --- /dev/null +++ b/misc/sulogin.c @@ -0,0 +1,9 @@ +#include <unistd.h> +#include <stdlib.h> +extern char **environ; + +void sulogin() /*EXTRACT_INCL*/ { + char *argv[2] = {"sulogin",0}; + execve("/sbin/sulogin",argv,environ); + _exit(1); +} diff --git a/misc/system_child_block.c b/misc/system_child_block.c new file mode 100644 index 0000000..7032f71 --- /dev/null +++ b/misc/system_child_block.c @@ -0,0 +1,9 @@ +#define SIGACTION_FUNCTIONS +#include "../process_defs.h" +extern int rt_sigprocmask(); + +void system_child_block(int type) /*EXTRACT_INCL*/ { + /* SIG_BLOCK, SIG_UNBLOCK */ + STATIC_SIGCHLD_MASK; + rt_sigprocmask(type,&sigchld_mask,0,sizeof(sigchld_mask)); +} diff --git a/misc/system_set_sigaction.c b/misc/system_set_sigaction.c new file mode 100644 index 0000000..04515c4 --- /dev/null +++ b/misc/system_set_sigaction.c @@ -0,0 +1,42 @@ +#define SIGACTION_FUNCTIONS +#include "../process_defs.h" + +typedef void (*sighandler_t)(int); +typedef struct { unsigned long sig[SIGSET_MASK_LEN_N]; } sigset_t; + +/* copy/paste from dietlibc! Felix, you are great! */ +struct sigaction { +#if defined(__alpha__) || defined(__ia64__) || defined(__hppa__) + sighandler_t sa_handler; + unsigned long sa_flags; + sigset_t sa_mask; +#elif defined(__mips__) + unsigned long sa_flags; + sighandler_t sa_handler; + sigset_t sa_mask; + void (*sa_restorer)(void); + int32_t sa_resv[1]; +#else /* arm, i386, ppc, s390, sparc, saprc64, x86_64 */ + sighandler_t sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + sigset_t sa_mask; +#endif +}; + +extern void sighandler(int sig); +extern void __restore(); +extern void __restore_rt(); +extern int rt_sigaction(); +#include "../byte_defs.h" + +void system_set_sigaction(int sig) /*EXTRACT_INCL*/ { + struct sigaction sa; + byte_zero(&sa, sizeof(sa)); + sa.sa_handler=sighandler; + sa.sa_flags=SA_FLAGS_number; +#ifndef INIT_SKIP_SIGRETURN + sa.sa_restorer=&(SA_RESTORER_function); +#endif + rt_sigaction(sig, &sa, 0, sizeof(sigset_t)); +} diff --git a/misc/try_helper.h b/misc/try_helper.h new file mode 100644 index 0000000..bdc7319 --- /dev/null +++ b/misc/try_helper.h @@ -0,0 +1,29 @@ +unsigned int s_len(const char * s) { + unsigned int len=0; + while (s[len]) ++len; + return len; +} + +char *fmt_ul(unsigned long u) { + static char strnum[48]; + char *hex = "0123456789abcdef"; + char *s = strnum+44; + *s = 0; + do { *--s = hex[(u % 16)]; u /= 16; } while(u); /* handles u==0 */ + *--s = 'x'; + *--s = '0'; + return s; +} + +char *fmt_o(unsigned char c) { + static char x[8]; + x[4] = 0; + x[3] = '0' + (c & 7); c >>= 3; + x[2] = '0' + (c & 7); c >>= 3; + x[1] = '0' + (c & 7); + x[0] = '\\'; + return x; +} + +void w(char *s) { write(1,s,s_len(s)); } +void wn(unsigned long u) { w(fmt_ul(u)); } diff --git a/misc/try_int.h2 b/misc/try_int.h2 new file mode 100644 index 0000000..c010eaf --- /dev/null +++ b/misc/try_int.h2 @@ -0,0 +1,5 @@ +#ifndef INT_DEFS_H +#define INT_DEFS_H +typedef unsigned Z uint32t; +typedef Z int32t; +#endif diff --git a/misc/trypagesize.c b/misc/trypagesize.c new file mode 100644 index 0000000..33c7cbb --- /dev/null +++ b/misc/trypagesize.c @@ -0,0 +1,5 @@ +#include <unistd.h> +int main() { + if (getpagesize() == 4096) return 0; + return 1; +} diff --git a/misc/tryprocess.c b/misc/tryprocess.c new file mode 100644 index 0000000..821e670 --- /dev/null +++ b/misc/tryprocess.c @@ -0,0 +1,132 @@ +#include "../ninitfeatures.h" +#include <unistd.h> +#include <signal.h> +#include "try_helper.h" + +#define ioctl libc_ioctl +#include <termios.h> +#undef ioctl +#include <sys/ioctl.h> + +#define w_sn_(a,b) w(a); wn(b); w("\n") +#define w_sp_(a,b,c) w(a); wn((void *)(&b) - (void *)(&c)); w("\n") +#define w_sns(a,b,c) w(a); wn(b); w(c) +#define w_ss_(a,b) w(a); w(b); w("\n") +#define w_o(X) w(fmt_o((unsigned char)X)) +#define w_to(t,X) w(t); w_o(X) + +#include "../struct_root.h" +INIT_ROOT_DEFINE(ch, char*); +INIT_ROOT_DEFINE(ui, unsigned int); + +#define UL sizeof(unsigned long) +#define MASK_LEN (_NSIG/(8 * UL)) +#define WORD(X) ((X-1)/(8*UL)) +#define MASK(X) (((unsigned long)1) << (X-1) % (8*UL)) + +int main() { + int i,k; + struct sigaction sa; + unsigned long uu[256]; + char *ss[4] = { "kbreq", "ctrlaltdel", "powerS", "levelU" }; + + w("#define NINIT_SERVICES_CODED\t\""); + for (k=4, i=0; i<4; i++) { + w_o(k); + k += 1 + s_len(ss[i]); + } + for (i=0; i<4; i++) { + w(ss[i]); + if (i<3) w("\\000"); + } + w("\"\n"); + + if (SIGWINCH < 256 && SIGINT < 256 && SIGPWR < 256 && SIGHUP < 256) { + w("#define NINIT_SIGNAL_HANDLER_CODED\t\""); + w_o(SIGWINCH); w_o(SIGINT); w_o(SIGPWR); w_o(SIGHUP); + w("\"\n"); + } + + if (SIGTERM < 256 && SIGALRM < 256 && SIGSTOP < 256 && + SIGCONT < 256 && SIGHUP < 256 && SIGINT < 256 && SIGKILL < 256) { + w("#define NSVC_SIGNAL_CODED\t\""); + w_to("t",SIGTERM); w_to("a",SIGALRM); w_to("p",SIGSTOP); + w_to("c",SIGCONT); w_to("h",SIGHUP); w_to("i",SIGINT); + w_to("k",SIGKILL); + w("\"\n"); + } + + w_sn_("#if 0\n\tdev_t\t", sizeof(dev_t)); + w_sn_("\tgid_t\t", sizeof(gid_t)); + w_sn_("\tuid_t\t", sizeof(uid_t)); + w_sn_("\tmode_t\t", sizeof(mode_t)); + + w_sn_("#endif\n#define X_TIOCGPGRP\t", TIOCGPGRP); + w("\n#ifdef SIGACTION_FUNCTIONS\n\n"); + +#ifndef SA_RESTORER +#define SA_RESTORER 0x04000000 +#endif + + w_sn_("#define SA_RESTART\t", SA_RESTART); + w_sn_("#define SA_NOCLDSTOP\t", SA_NOCLDSTOP); + + uu[0] = SA_RESTART | SA_NOCLDSTOP | SA_RESTORER; +#ifdef INIT_SKIP_SIGRETURN + w("#define INIT_SKIP_SIGRETURN\n"); + uu[0] = SA_RESTART | SA_NOCLDSTOP; +#endif + w_sn_("#define SA_FLAGS_number\t", uu[0]); + +#if defined(__i386__) + w("#define SA_RESTORER_function\t__restore"); + if (uu[0] & SA_SIGINFO) w("_rt"); +#endif + +#if defined(__x86_64__) + w("#define SA_RESTORER_function\t__restore_rt"); +#endif + w("\n"); + + w("\n#if 0\n"); + /* w_sn_("#define STAT_SIZE\t", sizeof(struct stat)); */ + w_sn_("#define SIGATION_SIZE\t", sizeof(sa)); + w_sn_("#define SIGSET_T_SIZE\t", sizeof(sa.sa_mask)); + w_sn_("#define SIGSET_WORD_N\t", WORD(SIGCHLD)); + w_sn_("#define SIGSET_MASK_N\t", MASK(SIGCHLD)); + + w_sp_("\tsa_handler offset\t", sa.sa_handler, sa); + w_sp_("\tsa_flags offset\t", sa.sa_flags, sa); + w_sp_("\tsa_restorer offest\t",sa.sa_restorer, sa); + w_sp_("\tsa_mask offset\t", sa.sa_mask, sa); + w("#endif\n\n"); + + for (i=0; i<256; i++) uu[i] = 0; + uu[WORD(SIGCHLD)] = MASK(SIGCHLD); + w_sn_("#define SIGSET_MASK_LEN_N\t", MASK_LEN); + w_sns("#define STATIC_SIGCHLD_MASK unsigned long sigchld_mask[", + MASK_LEN, "] = { "); + + for (i=0;; ) { + wn(uu[i]); + if (++i == MASK_LEN) break; + w(", "); + } + + w(" }\n" + "\n#else\n" + "#include \"struct_root.h\"\n"); + + if (sizeof(struct ch) > sizeof(struct ui)) { + w("#define INIT_NAME_IS_UINT\n"); + w_sn_("#define PROCESS_SIZE ", sizeof(struct ui)); + w("INIT_ROOT_DEFINE(process, uint32t) *root;\n"); + } else { + w("#undef INIT_NAME_IS_UINT\n"); + w_sn_("#define PROCESS_SIZE ", sizeof(struct ch)); + w("INIT_ROOT_DEFINE(process, char*) *root;\n"); + } + + w("#endif\n"); + return 0; +} diff --git a/misc/tryulong32.c b/misc/tryulong32.c new file mode 100644 index 0000000..e0adc6d --- /dev/null +++ b/misc/tryulong32.c @@ -0,0 +1,6 @@ +int main() { + unsigned long u=1,k=0; + for (; k<32; k++) u += u; + if (!u) return 0; + return 1; +} diff --git a/mmap_alloca.h b/mmap_alloca.h new file mode 100644 index 0000000..20b9d89 --- /dev/null +++ b/mmap_alloca.h @@ -0,0 +1,51 @@ +#ifndef INIT_MMAP + +#define depends_alloca(N) alloca(N) +#define read_alloca(N) alloca(N) +#define INIT_FREE_MEMBLOCKS(X) X +#define free_execve(...) execve(__VA_ARGS__) + + +#else +#include <sys/mman.h> +#include <sys/shm.h> /* for PAGE_SIZE */ +#ifndef PAGE_SIZE +#define PAGE_SIZE 4096 +#endif + +#define depends_alloca(N) mmap_alloca(N) +#define read_alloca(N) \ + ((read_buf) ? read_buf : (read_buf=mmap_alloca(N))) + +#define INIT_FREE_MEMBLOCKS(X) read_buf=0; mmap_free(); X +#define free_execve(...) mmap_free(); execve(__VA_ARGS__) + +#define mem_x_size ((sizeof(struct memalloc) + 16) & ~15) +static struct memalloc *mroot; +static void *read_buf; + +static void *mmap_alloca(uint32t n) { + n = (n + 16) & ~15; + if (mroot == 0 || n + mem_x_size >= mroot->r) { + struct memalloc *m; + uint32t len = (n + (PAGE_SIZE + mem_x_size)) & ~(PAGE_SIZE-1); + m = mmap(0,len,PROT_READ|PROT_WRITE,MAP_ANONYMOUS|MAP_PRIVATE,-1,0); + if (m == (struct memalloc *)-1) return 0; + m->x = mroot; /* previous block */ + m->a = len; + m->r = len; + mroot = m; + } + mroot->r -= n; + return (void *)mroot + mroot->r; +} +#undef mem_x_size + +static void mmap_free() { + while (mroot) { + void *x = mroot->x; + munmap(mroot,mroot->a); + mroot = x; + } +} +#endif @@ -0,0 +1,345 @@ +#define INIT_PROGRAM +#include "ninit.h" + +/* load a service into the process data structure and return index or -1 + * if failed */ +static int loadservice(char *s) { + struct process tmp; + int fd; + if (*s==0 || *s=='#') return -1; + fd=findservice(s); + if (fd>=0) return fd; + if (chdir(initroot) || chdir(s)) return -1; +#ifdef INIT_CREATE_INOUT_PIPE + if (SYS_mknod("log/in",S_IFIFO|0600,0)==0) symlink("log/in","out"); +#endif + byte_zero(&tmp, sizeof(tmp)); + tmp.startedat = time(0); + tmp.pr_respawn = (access("respawn", R_OK)==0); + return addprocess(&tmp, s); +} + +static void childhandler(); +static int do_poll(struct pollfd *pfd, int timeout) { + int k, n = timeout & 3; + for (k=0; k<n; k++) { + pfd[k].events = POLLIN; + pfd[k].revents = 0; + } + CHILD_UNBLOCK; + k=poll(pfd,n,timeout); + CHILD_BLOCK; + if (k<0) { + if (errno==EINTR) childhandler(); +#ifdef INIT_POLL_FAILED + else { write(1,"poll failed!\n",13); sulogin(); } +#endif + } + return k; +} + +static int startbyind(int service, int father) { + struct process *pr = root + service; + char *name = process_name(pr); + pid_t pid; + struct timespec req = {0,500000000}; + + if (pr->pid || pr->pr_circular) return service; + pr->pr_circular=1; + pr->father=father; + pr->cron=0; +#if INIT_HISTORY > 0 + for (pid = INIT_HISTORY; pid>1; --pid) history[pid] = history[pid-1]; + history[1]=service+1; +#endif + if (chdir(initroot)) return -1; + while ((pid=fork()) < 0) nanosleep(&req,0); + if (pid==0) { + CHILD_UNBLOCK; + if (chdir(initsysdir)==0) { + char *aa[5]; + INIT_ARGS5(aa, pr->pr_end ? "end" : "./run",name,initroot,initsysdir,0); + if (time(0) == pr->startedat) nanosleep(&req,0); + free_execve("./run",aa,environ); + } + _exit(1); + } + pr->pid=pid; + pr->startedat=time(0); + if (chdir(name)==0) { + int fd; + if (pr->pr_end) pr->pr_end = 0; + else pr->pr_end = (access("end",X_OK)==0); + + if ((fd=open("sync", O_RDONLY)) >= 0) { + struct pollfd pfd[2]; + unsigned int u; + byte_zero(pfd, sizeof(pfd)); + read(fd, pfd, sizeof(pfd)-1); + close(fd); + + if ((u=atoulong((void *)pfd)) == 0) u = -1; + pfd->fd = -1; + do { + do_poll(pfd, 1001); /* must be 4k+1 */ + if (pr->pid < 2) break; + } while (u--); + } + } + return service; +} + +static int startbyname(char *name,int father) { + char *s; + int fd,len,service=loadservice(name); + if (service<0) return -1; + name = root_name(service); +#ifdef INIT_BLACK + if (father>=0) + for (len=1; (s=Argv[len]); len++) + if (*s=='#' && !str_diff(s+1,name)) + return service; +#endif +#ifdef INIT_LOG_SERVICE + len = str_len(name); + s = alloca(len+5); if (s==0) return -1; + byte_copy(s,len,name); + byte_copy(s+len,5,"/log"); + startbyname(s,service); +#endif + + if (chdir(initroot) || chdir(name)) return -1; + if ((fd = open("depends", O_RDONLY)) >= 0) { + char *p, exitasapl=0; + if (GLOBAL_READ(fd,s, len,32000)) { close(fd); return 0; } + close(fd); + s[len]=0; + for (p=s; ;p=++s) { + while (*s && *s!='\n') s++; + if (*s==0) ++exitasapl; + *s=0; + startbyname(p,service); + if (exitasapl) break; + } + } + return startbyind(service,father); +} + +/* return -1 on error */ +static int restartservice(char *s) { + int n=loadservice(s); + if (n>=0 && root[n].pid<2) { + if (start_time) root[n].cron = start_time; + else { + root[n].pid=0; + circsweep(); + n=startbyname(s,-1); + } + } + start_time = 0; + return n; +} + +static void handlekilled(int ind) { + struct process *pr = root + ind; + next_cron = 0; + pr->pr_finish = 1; + pr->pid = 0; + if (pr->pr_end || pr->pr_respawn) { + circsweep(); + startbyind(ind,pr->father); + } else { + pr->startedat=time(0); + pr->pid += 1; + } +} + +static void childhandler() { + int ind; + pid_t pid; + if (do_update) return; + while ((pid=waitpid(-1,0,WNOHANG))) { + if (pid < 0) { +#ifdef INIT_EXIT_WARNING + static char saidso; + if (!saidso) { write(2,"all services exited.\n",21); ++saidso; } +#endif + return; + } + for (ind=0; ind<=maxprocess; ind++) + if (root[ind].pid==pid) { + handlekilled(ind); + break; + } + } +} + +static void do_initctl(struct pollfd *pfd) { + int fd; + if (restartservice("sysvinit") >= 0) { + if ((fd=open(INIT_FIFO,O_RDWR)) >= 0) + initctl=fd; + } else ++initctl; + pfd[1].fd = initctl; + fcntl(pfd[1].fd,F_SETFD,FD_CLOEXEC); +} + +static void read_infd() { + char *b1, *other, *buf; + struct process *pr; + int idx, len, offset; + uint32t u32; + + buf = read_alloca(384); + if (buf==0 || (len=read(infd,buf,380)) <2) return; + + b1 = buf + 1; + buf[len] = 0; buf[len+1] = 0; + offset = str_len(buf) + 1; + other = buf + offset; + u32 = atoulong(other); + next_cron = 0; + + switch (buf[0]) { + case 'D': + if (*b1=='M') t_write(mem.x,mem.a); + else { + if (*b1=='1') do_update = 1; + t_write(mem.x+mem.r, mem.a-mem.r); /* names + history */ + t_write(root, mem.l); /* precess */ + } + break; + case 'U': /* U\0argv[0] or Uservice\0 */ + if (*b1==0) { + char *aa[3]; INIT_ARGS3(aa, other, "", 0); + execve(other,aa,environ); + } else + if (len >= offset + PROCESS_SIZE && + addprocess(other,b1) >= 0) goto ok; + goto error; + case 's': + start_time = u32; + if (restartservice(b1) < 0) goto error; +ok: t_write("1",1); break; +error: t_write("0",1); break; + + default: + if ((idx=findservice(b1)) <0) goto error; + pr = root + idx; + + switch(buf[0]) { + case 'r': pr->pr_respawn = (other[0] != 0); goto write_pr; + case 'P': + if ((pid_t)u32<2 || kill(u32,0)) goto error; + pr->pid = u32; goto write_pr; + case 'c': pr->cron = u32; + case 'p': +write_pr: + t_write(pr, sizeof(struct process)); + } + } +} + +int main(int argc, char *argv[]) { + struct pollfd pfd[12]; + time_t now; + int i; +#ifdef INIT_BLACK + Argv=argv; +#endif + mem.r = INIT_ALLOC_BUFFER; + for (i=1; i<argc; i++) + if (argv[i][0]=='-') { + char *p = argv[i]+2; + switch (p[-1]) { + case 'M': mem.r = atoulong(p); break; +#ifdef INIT_HOME + case 'H': initroot = p; break; + case 'S': initsysdir = p; break; +#endif + default: p[-2] = '#'; /* -sshd --> #sshd */ + } + } + + mem.r &= 0xfff8; /* max 64K */ + mem.a = mem.r + (INIT_HISTORY+1) * sizeof(unsigned short); + mem.x = alloca(mem.a); /* if it fails bummer */ + history = mem.x + mem.r; + byte_zero(history, (INIT_HISTORY+1) * sizeof(unsigned short)); + ((unsigned char*)history)[1] = INIT_HISTORY; + + if (getpid()==1) { + set_reboot(0); + i = open("/dev/console",O_RDWR|O_NOCTTY); + if (i>0) { dup2(i,0); close(i); } + ioctl(0, KDSIGACCEPT, SIGWINCH); + } + + set_sa(SIGCHLD); + set_sa(SIGINT); /* ctrl-alt-del */ + set_sa(SIGWINCH); /* keyboard request */ +#ifdef INIT_SYSVINIT_SIGNALS + set_sa(SIGPWR); /* ifdef INIT_POWERSTATUS start powerZ */ + set_sa(SIGHUP); /* ifdef INIT_SIGHUP start levelU */ + set_sa(SIGUSR1); /* ifdef INIT_SIGUSR1 reopen /dev/initctl */ +#endif + CHILD_BLOCK; + + if (chdir(initroot) || + (infd=open("in",O_RDWR)) < 0 || + (outfd=open("out",O_RDWR|O_NONBLOCK)) < 0) { +#ifdef INIT_PIPES_ERROR + write(1,"pipes error\n",12); sulogin(); +#endif + } else { + int fd=open(".sync", O_RDONLY); + while ((i=read(fd,pfd,sizeof(pfd))) > 0) write(1,pfd,i); + close(fd); + } + + fcntl(infd,F_SETFD,FD_CLOEXEC); + fcntl(outfd,F_SETFD,FD_CLOEXEC); + + if (argv[argc-1][0] == 0) { + ++do_update; + t_write("8",1); + } else { + for (i=1; i<argc; i++) restartservice(argv[i]); + if (maxprocess < 0) restartservice("default"); + } + + pfd[0].fd = infd; + pfd[1].fd = -1; + + for (;;) { + for (i=0; i<4; i++) + if (got_sig[i]) { + char *xx = NINIT_SERVICES_CODED; + got_sig[i]=0; restartservice(xx + xx[i]); + } + childhandler(); + + if ((time(&now)) > next_cron) { + time_t t; next_cron = now + 1800; + for (i=0; i<=maxprocess; i++) { + struct process *pr = root + i; + if (pr->pid > 1 && kill(pr->pid, 0)) handlekilled(i); + + if (pr->pid < 2 && (t=pr->cron) > 0) { + if (t < now) restartservice(root_name(i)); + if (t < next_cron) next_cron = t; + } + } + } + + if ((i=do_poll(pfd, 5002)) == 0) { /* timeout; must be 4k+2 */ + INIT_FREE_MEMBLOCKS(do_update=0); + if (initctl < -1) do_initctl(pfd); + continue; + } + if (i>0) { + if (pfd[0].revents) read_infd(); + if (pfd[1].revents) restartservice("sysvinit"); + } + } +} @@ -0,0 +1,82 @@ +#include "ninitfeatures.h" +#include "process_defs.h" + +#ifndef INIT_NAME_IS_UINT +#define root_name(J) root[J].name +#define process_name(P) P->name +#define alloc_name_set(N) N +#define process_name_set name +#define root_names_len (mem.x + mem.a - (void*)root[0].name) + +#else +#define root_name(J) (mem.x + root[J].name) +#define process_name(P) (mem.x + P->name) +#define alloc_name_set(N) ((void*)N - mem.x) +#define process_name_set mem.r +#define root_names_len (mem.a - root[0].name) +#endif + +#ifdef INIT_PROGRAM +#include <time.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/poll.h> +#include <sys/wait.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/reboot.h> +#include <linux/kd.h> +#include "initreq.h" +#endif + +#if ((INIT_HISTORY<0) || (INIT_HISTORY>255)) +#error ***** INIT_HISTORY must be between 0 and 255 ***** +#endif + +static int infd, outfd; +static int maxprocess=-1; +static struct memalloc mem; + +#ifdef INIT_PROGRAM + +#ifdef INIT_HOME +static char *initroot = INITROOT; +static char *initsysdir = INITSYSDIR; +#else +#define initroot INITROOT +#define initsysdir INITSYSDIR +#endif + +#ifdef INIT_BLACK +static char** Argv; +#endif + +static char do_update; +static time_t next_cron; +static uint32t start_time; +static int initctl = -5; +static unsigned short *history; + +#include "findservice.h" +#include "addprocess.h" +#include "t_write.h" +#include "mmap_alloca.h" +#include "sighandler.h" +#include "uid.h" + +#ifndef INIT_CHILD_BLOCK +#define CHILD_BLOCK +#define CHILD_UNBLOCK +#else +#if INIT_SYSTEM +#define CHILD_BLOCK system_child_block(SIG_BLOCK) +#define CHILD_UNBLOCK system_child_block(SIG_UNBLOCK) +#else +#define CHILD_BLOCK child_block(SIG_BLOCK) +#define CHILD_UNBLOCK child_block(SIG_UNBLOCK) +#endif +#endif + +#endif diff --git a/ninit.spec b/ninit.spec new file mode 100644 index 0000000..6c1fd3e --- /dev/null +++ b/ninit.spec @@ -0,0 +1,60 @@ +Summary: small init with build-in SVC and cron +Name: ninit +Version: 0.14 +Release: 1 +Group: System Environment/Daemons +Packager: Nikola Vladov <[email protected]> +Source: http://riemann.fmi.uni-sofia.bg/ninit/ninit-%{version}.tar.bz2 +URL: http://riemann.fmi.uni-sofia.bg/ninit/ +License: GPL +Prefix: / +BuildRoot: %{_tmppath}/%{name}-%{version}-root + +%description + +Ninit is a small daemon which can be PID 1. It has build-in SVC and cron. +Read more about it on http://riemann.fmi.uni-sofia.bg/ninit/ + +%prep + +%setup -q + +%build +MYARCH=`uname -m | sed -e's/i[4-9]86/i386/' -e's/armv[3-6]t\?e\?[lb]/arm/'` +test "i386" != ${MYARCH} -a "x86_64" != ${MYARCH} && MYARCH=withdiet +make ${MYARCH} prefix=${RPM_BUILD_ROOT} +test -d bin-${MYARCH} && cp bin-${MYARCH}/* . + +%install +mkdir -p ${RPM_BUILD_ROOT}/usr/share/man +make install DESTDIR=${RPM_BUILD_ROOT} +rm -f ${RPM_BUILD_ROOT}/etc/ninit/in ${RPM_BUILD_ROOT}/etc/ninit/out + +%clean +rm -rf ${RPM_BUILD_ROOT} + +%post +test -p /etc/ninit/in || mkfifo -m 600 /etc/ninit/in +test -p /etc/ninit/out || mkfifo -m 600 /etc/ninit/out + +aa=`readlink /proc/1/exe` +if test "$aa" = "/sbin/ninit" ; then + /sbin/ninit-reload -v -u /sbin/ninit +else + echo See the home page of ninit how to prepare the host to boot + echo with /sbin/ninit instead of default /sbin/init. + echo http://riemann.fmi.uni-sofia.bg/ninit/ +fi +%postun + +%files +%defattr(-,root,root) +/sbin +/usr +/etc +/bin +%doc README CHANGES + +%changelog +* Thu May 14 2008 Nikola Vladov <[email protected]> +- Create rpm diff --git a/ninitfeatures.h b/ninitfeatures.h new file mode 100644 index 0000000..be2ab39 --- /dev/null +++ b/ninitfeatures.h @@ -0,0 +1,199 @@ +/* bellow is the variable INIT_PRIVATE_SETUP + Fill private changes there! */ + +#ifndef NINITFEATURES_H +#define NINITFEATURES_H + +#define INITROOT "/etc/ninit" +#define INITSYSDIR "sys" + +#define INIT_POWERSTATUS "/etc/powerstatus" +#define SYSVINIT_VERSION "2.86" + + /* comment next line if you don't have system flock */ +#define HAVE__NR_flock + + /* checks the environ vars: NINIT_HOME and INIT_HOME. + default is only the first */ +// #define INIT_TWO_ENV_HOME + + /* if your kernel has sigreturn function uncomment next line */ +// #define INIT_SKIP_SIGRETURN + + + /* ------ setup for serdo ----- */ + + /* simple echo; don't support esacpes: \a \t ... */ +#define SERDO_WANT_echo + + /* see manpage killall5(8) */ +#define SERDO_WANT_killall5 + + /* VAR1=val1 VAR2=val2 ... command ...; see sh(1) */ +#define SERDO_WANT_environ_in_command + + /* max total new variables for export */ +#define SERDO_MAX_NEW_ENVIRON 128 + + /* Next is a big security hole! It's similar to dot in PATH + Idea: some user type: echo /bin/rm -rf / > /tmp/script + and the sysadmin execs serdo in /tmp */ +// #define SERDO_EXEC_script + + + /* ------ setup for run ----- */ + + /* default maximal timout for waiting a service to finish */ +#define RUN_MAXWAIT 600 + + /* if defined check gid file in the service directory */ +// #define RUN_WANT_GID_FILE + + + /* ------ setup for nsvc ----- */ + + /* /etc/ninit/ops/// --> ops; only for nsvc */ +#define CLEAN_SERVICE + + + /* ----- setup for ninit ----- */ +#ifdef INIT_PROGRAM + + /* must be between 0 and 255. length of history; */ +#define INIT_HISTORY 31 + + /* if a service has dir log it is startded first. + you can skip this and include all log in depends. */ +#define INIT_LOG_SERVICE + + /* ninit automatic creates in/out named pipes for log-services */ +#define INIT_CREATE_INOUT_PIPE + + /* next tree lines are debug warnings. + you can comment them if ninit works stable. */ +#define INIT_PIPES_ERROR + + /* warning if poll filed; never happen */ +#define INIT_POLL_FAILED + + /* say that all services are exited. more simple: nsvc -L */ +#define INIT_EXIT_WARNING + + /* ninit will use different service dir with option -H. + example: /sbin/ninit -H/etc/ninit.test + The {in,out} pipes must be links to /etc/ninit/{in,out}. + This is because they are coded in nsvc and ninit-reload. */ +#define INIT_HOME + + /* sigaction on SIGUSR1, SIGPWR, SIGHUP. Comment next to uncatch + above signals. Catching them makes ninit 68 bytes longer. */ +#define INIT_SYSVINIT_SIGNALS + + /* skip services with names '-blabla' or '#blabla' on startup */ +// #define INIT_BLACK + + /* unblock/block SIGCHLD near to main poll loop */ +// #define INIT_CHILD_BLOCK + + /* if you use ninit with -Mn and n>3500 uncomment next line. + see total/used memory with: + ninit-reload -m | wc -c + nsvc -D */ +// #define INIT_TIMEOUT_WRITE + + /* uses mmap for depends instead of alloca. If your depeneds + files are too large try this ;-) */ +// #define INIT_MMAP +#endif + + +/* one service (i386) uses 21 + strlen(service) bytes RAM */ +#ifndef INIT_ALLOC_BUFFER +#ifdef INIT_PROGRAM +#ifndef INIT_MMAP +#define INIT_ALLOC_BUFFER 1536 +#else +#define INIT_ALLOC_BUFFER 2800 +#endif +#endif + +#ifdef SVC_PROGRAM +#define INIT_ALLOC_BUFFER 3840 +#endif +#endif + +#ifndef INIT_ALLOC_BUFFER +#define INIT_ALLOC_BUFFER 8192 +#endif + +// #define INIT_PRIVATE_SETUP + +#ifdef INIT_PRIVATE_SETUP +// #undef INIT_HOME +#undef INIT_BLACK +#undef INIT_SYSVINIT_SIGNALS + +#undef INIT_PIPES_ERROR +#undef INIT_POLL_FAILED +#undef INIT_EXIT_WARNING + +#undef INIT_LOG_SERVICE +#undef INIT_CREATE_INOUT_PIPE +// #define SYSVINIT_DUMP_INITREQ +#endif + +/* -------- stop changes here ;-) ---------- */ +#ifdef INIT_PROGRAM +#ifndef INIT_HISTORY +#define INIT_HISTORY 0 +#endif + +#ifndef INIT_LOG_SERVICE +#undef INIT_CREATE_INOUT_PIPE +#endif +#endif + +#ifndef INIT_TIMEOUT_WRITE +#if (INIT_ALLOC_BUFFER + 0 > 3600) +#define INIT_TIMEOUT_WRITE +#endif +#endif + +#include <sys/types.h> +#include "all_defs.h" + +#define GLOBAL_fstat_READ(fd,st,s, len,max_len) \ + system_fstat(fd,&st) || (unsigned int)(len=st.st_size) > max_len || \ + (s=alloca(len+1))==0 || read(fd,s,len) != len + +#define GLOBAL_READ(fd,s, len,max_len) \ + (len=lseek(fd,0,SEEK_END)) < 0 || \ + len > max_len || lseek(fd,0,SEEK_SET) || \ + (s=alloca(len+1)) == 0 || read(fd,s,len) != len + +extern char **environ; +extern const char *errmsg_argv0; + +#define INIT_ARGS1(Z,a) Z[0]=a +#define INIT_ARGS2(Z,a,b) do { Z[0]=a; Z[1]=b; } while(0) +#define INIT_ARGS3(Z,a,b,c) do { Z[0]=a; Z[1]=b; Z[2]=c; } while(0) +#define INIT_ARGS4(Z,a,b,c,d) do { Z[0]=a; Z[1]=b; Z[2]=c; Z[3]=d; } while(0) +#define INIT_ARGS5(Z,a,b,c,d,e) do { Z[0]=a; Z[1]=b; Z[2]=c; Z[3]=d; Z[4]=e; } while(0) +#define INIT_ARGS6(Z,a,b,c,d,e,f) do { Z[0]=a; Z[1]=b; Z[2]=c; Z[3]=d; Z[4]=e; Z[5]=f; } while(0) +#define INIT_ARGS7(Z,a,b,c,d,e,f,g) do { Z[0]=a; Z[1]=b; Z[2]=c; Z[3]=d; Z[4]=e; Z[5]=f; Z[6]=g; } while(0) +#define INIT_ARGS8(Z,a,b,c,d,e,f,g,h) do { Z[0]=a; Z[1]=b; Z[2]=c; Z[3]=d; Z[4]=e; Z[5]=f; Z[6]=g; Z[7]=h; } while(0) + +#define msg(...) err(1,__VA_ARGS__,(char*)0) +#define carp(...) err(2,__VA_ARGS__,(char*)0) +#define die(n,...) do { err(2,__VA_ARGS__,(char*)0); _exit(n); } while(0) +#define errmsg_iam(X) errmsg_argv0 = X + +#ifndef INIT_TWO_ENV_HOME +#define INIT_ENV_GET_HOME(H,A,B) H=env_get(A) +#else +#define INIT_ENV_GET_HOME(H,A,B) H=env_get(A); if (!H) H=env_get(B) +#endif +#undef INIT_TWO_ENV_HOME + +#define BUFFER_TMP_LEN 1500 +#endif /* end of file */ diff --git a/nkillall.c b/nkillall.c new file mode 100644 index 0000000..0abcaef --- /dev/null +++ b/nkillall.c @@ -0,0 +1,179 @@ +#include <unistd.h> +#include <fcntl.h> +#include <time.h> +#include <signal.h> +#include <alloca.h> +#include <utmp.h> +#include <errno.h> +#include "ninitfeatures.h" +#include "process_defs.h" +#include "utmp_defs.h" +#include "uid.h" +#include "check_opt.h" + +static int cfg_verbose; + +void sighandler(int sig) { (void)sig; } + +static void deep_sleep(char *x) { + time_t t = x_atoi(x); + time_t deedline = time(0) + t; + if (t<=0) return; + if (cfg_verbose>1) msg("Sleeping: ", x); + while (1) { + nano_sleep(1,0); + if (time(0) >= deedline) break; + } +} + +static void print_escape(char *x, int wall) { + char ch, *y, *start, *from = "abefnrtv\\c", *to= "\a\b\033\f\n\r\t\v\\"; + unsigned long len; + start = alloca(str_len(x) + 3); + for (y=start; (ch=*x); x++) { + if (ch == '\\') { + unsigned long u; + len = scan_8ulong(x+1, &u); + if (len) { /* 012...9 */ + ch = u; + x += len; + } else { + len = str_chr(from, x[1]); + switch (from[len]) { + case 0: break; + case 'c': goto do_it; + default: /* \a\b... */ ++x; ch = to[len]; + } + } + } + *y++ = ch; + } + *y++ = '\n'; + + do_it: + len = y-start; + + if (wall==0) write(1, start, len); + else { + struct utmp u; + int fd, r; + char line[8 + sizeof(u.ut_line)]; + + fd = open(_PATH_UTMP, O_RDONLY | O_NOCTTY); + if (fd < 0) return; + + while (utmp_io(fd, &u, F_RDLCK)) { + if (u.ut_type != USER_PROCESS) continue; + if (u.ut_user[0] == 0 || u.ut_pid < 2 || + u.ut_line[0] == 0 || u.ut_line[0] == '/') continue; + + y = line; + y += str_copyn(y, "/dev/", 8); + y += str_copyn(y, u.ut_line, sizeof(u.ut_line)); + y[0] = 0; + if (line[str_chr(line, '.')]) continue; + + if (kill(u.ut_pid, 0) && errno == ESRCH) continue; + r = open(line, O_WRONLY | O_NOCTTY | O_NDELAY); + if (r < 0) continue; + + write(r, start, len); + close(r); + } + close(fd); + } +} + +#define Kill_Help \ +"Usage:\n",me, \ +" -[vq] [-s secs] [-M|W mesg] [-signum] ... [-E program [arg[s]]\n" \ +"\t-s secs:\tsleep secs\n" \ +"\t-M mesg:\twrite mesg to stdout\n" \ +"\t-W mesg:\twrite mesg to logged users\n" \ +"\t-sugnum:\tsignal number\n" \ +"\t-v[v]:\t\tbe verbose\n" \ +"\t-q:\t\tquiet mode; ignores SIGINT signal\n\n" \ +"Some signals can be codded. Only the first letter is important!\n" \ +"\t-p:\tSIGSTOP\n" \ +"\t-c:\tSIGCONT\n" \ +"\t-h:\tSIGHUP\n" \ +"\t-a:\tSIGALRM\n" \ +"\t-i:\tSIGINT\n" \ +"\t-t:\tSIGTERM\n" \ +"\t-k:\tSIGKILL\n\n" \ +"Option -E must be last. Examples:\n ", \ +me," -s2 -M'Sending all processes SIGTERM ...' -term -cont \\\n" \ +"\t-s6 -M'Sending all processes SIGKILL ...' -9 \\\n" \ +"\t-s1 -E /path/to/program arg1 arg2 ...\n\n ", \ +me," -q -vv -s1 -15 -cont -s6 -kill -s1" \ +" -E/path/to/prog arg(s) ..." + +int main(int argc, char **argv) { + char *x, *me = argv[0]; + char *last_msg = "\\c"; + errmsg_iam(me); + if (argc<2) { + help: + errmsg_iam(0); + carp(Kill_Help); + _exit(1); + } + argv++; + x = argv[0]; + if (x[0]=='-' && x[1]=='h') goto help; /* -h... --help */ + + opendevconsole(); + + /* ignore next signals */ + set_sa(SIGQUIT); set_sa(SIGCHLD); set_sa(SIGHUP ); + set_sa(SIGTSTP); set_sa(SIGTTIN); set_sa(SIGTTOU); + + while (argv[0] && argv[0][0]=='-') { + int sig=0, cfg_wall=0; + char *y = argv[0] + 1; + if ((unsigned int)(*y - '0') < 10) { + sig = x_atoi(y); + goto again; + } + + switch(*y) { + case 'v': cfg_verbose++; if (y[1]=='v') cfg_verbose++; break; + case 'q': set_sa(SIGINT); break; + case 's': chk_opt(argv,x); deep_sleep(x); break; + case 'W': ++cfg_wall; + case 'M': chk_opt(argv,x); + if (x[0] == '%' && x[1] == 0) x = last_msg; + else last_msg = x; + print_escape(x, cfg_wall); + break; + case 'E': + chk_opt(argv,x); *argv = x; + execve(argv[0], argv, environ); + carp("Unable to exec: ", argv[0]); + _exit(1); + default: +#ifdef NSVC_SIGNAL_CODED + { + unsigned char *S, *Sig = (unsigned char *)NSVC_SIGNAL_CODED; + for (S=Sig; *S; S += 2) + if ((unsigned char)*y == *S) { sig = S[1]; goto again; } + } +#else +#define kk(C,S) case C: sig=S; break + kk('t',SIGTERM); kk('a',SIGALRM); kk('p',SIGSTOP); kk('c',SIGCONT); + kk('h',SIGHUP); kk('i',SIGINT); kk('k',SIGKILL); +#endif + goto help; + } + + again: + if (sig > 0) { + sync(); + if (cfg_verbose) msg("Sending signal: ", y); + if (kill(-1, sig)) carp("Unable to send signal: ", y); + } + argv++; + } + sync(); + return 0; +} @@ -0,0 +1,415 @@ +#define SVC_PROGRAM +#include <fcntl.h> +#include <time.h> +#include <sys/file.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <errno.h> +#include "ninit.h" +#include "nsvc_buffer.h" + +extern int ioctl(); + +static char **Names_skip, **NamesX, *buf, *initroot, *nsvc_other, respmode; +static int NamesI, do_update, tty = -111; + +static void e(int n) { buffer_flush(buffer_1); _exit(n); } +static void die_xx(char *s) { errmsg_iam("nsvc"); err(2,s,0); _exit(1); } + +#include "get_services.h" +#include "findservice.h" +#include "open_inout.h" +#include "tryservice_nsvc.h" + +static char *get_name() { + char *x, *s, **skp; + again: + if (NamesI >= 0) { + x = (NamesI <= maxprocess) ? root_name(NamesI) : 0; + ++NamesI; + } else { + x = *NamesX; + ++NamesX; + } + if (x) + for (skp=Names_skip; (s=*skp); skp++) + if (!str_diff(s,x)) goto again; + return x; +} + +static void close_inout() { + close(infd); infd = -1; + close(outfd); outfd = -1; +} + +static int __findservice(char *service) { + int idx; + get_services(); + idx=findservice(service); +#ifdef CLEAN_SERVICE + if (idx<0) idx=findservice(cleanservice(service)); +#endif + return idx; +} + +void print_pid(char *service, pid_t pid) { + errmsg_iam("nsvc"); + carp(service,(pid < 0) ? ": no such service" : ": service not running"); +} + +/* return PID, -1 if service is not loaded */ +static pid_t __readpid(char *service, int verbose) { + pid_t idx=__findservice(service); + if (idx >= 0) idx = root[idx].pid; + if (verbose && idx<2) + print_pid(service, idx); + return idx; +} + +static char *fu_x(uint32t u, int len) { /* len must be max 10 !!! */ + char *x = fu(u); + int y = str_len(x); + while (y < len) { *--x = ' '; y++; } + return x; +} + +static void fs_x(const char *s, int len) { + int k = str_len(s); + outs(s); + if (k >= len) outc('\t'); + else while (k++ < len) outc(' '); +} + +static void fmt_time(unsigned long up) { + unsigned long u; + u = up % 60; up /= 60; + fmt_color(fu_x(u, 4),'6'," "); + if (up) { u = up % 60; up /= 60; fmt_color(fu_x(u, 2),'4'," "); } + if (up) { u = up % 24; up /= 24; fmt_color(fu_x(u, 2),'5'," "); } + if (up) fmt_color(fu_x(up,4),'2',""); +} + +static int fmt_service(int i, int flagtty) { + struct process *pr = root + i; + pid_t pid = pr->pid; + time_t cr, uptime; + static time_t now; + + if (tty==-111) { +#if defined(INIT_SYSTEM) + pid_t dummy; + tty = (ioctl(1, X_TIOCGPGRP, &dummy) == 0); +#else + tty=isatty(1); +#endif + } + + if (!now) now=time(0); + uptime = now - pr->startedat; + if (uptime<0) uptime=0; + + if (flagtty || tty) { + char *name=root_name(i); + if (flagtty<=4 && tty) { + char flags[8], *x, ch; + int len; + + if (errmsg_argv0) { outs(errmsg_argv0); outs(": "); } + fs_x(name, 16); + + switch (pid) { + case 0: x=" down"; ch='7'; break; + case 1: x="finish"; ch='2'; break; + default: + if (pr->pr_respawn) ch='1'; else ch='4'; + x=fu_x(pid,6); + } + fmt_color(x,ch," "); + + len=0; + if (pr->pr_respawn) flags[len++] = 'R'; + if (pr->cron) flags[len++] = 'C'; + if (pr->pr_end) flags[len++] = 'E'; + flags[len] = 0 ; + fs_x(flags, 3); + + fmt_time(uptime); + + if ((cr = pr->cron)) { + fmt_color("\tnext cron",'1',":"); + if (cr > now) fmt_time(cr-now); + else outs(" waititing"); + outc('\t'); + fmt_color(fu(cr), '8', ""); + } + outc('\n'); + } + else + msg(name); + } else { + errmsg_iam(0); + msg(fu(pid)," ",fu(uptime)); + } + + if (pid==0) return 2; else if (pid==1) return 3; else return 0; +} + +static void dumphistory() { + int j; + if (!maxhistory) { + carp("ninit compiled without history support"); + return; + } + errmsg_iam(0); + for (j=0; j<maxhistory; j++) + if (--history[j] <= maxprocess) { + fmt_service(history[j], 4+root[history[j]].pr_circular); + root[history[j]].pr_circular = 1; + } +} + +static void dumpdependencies(char* service, unsigned int skip) { + int i,idx; + idx=__findservice(service); + if (idx<0) { print_pid(service, -1); return; } + + errmsg_iam(0); + for (i=0; i<=maxprocess; ++i) { + if (root[i].father==idx && i!=idx) { + char *name = root_name(i); + int k=skip; + while (k-->0) outs(" "); + msg(name); + if (skip<16) dumpdependencies(name,skip+1); + else msg(buf," ...",name); + } + } +} + +static void wait_childs(int len) { + unsigned wtime; + pid_t i, pids[len]; + char *x; + + for (len=0; (x=get_name());) + if ((pids[len]=__readpid(x, 0)) > 1) ++len; + + close_inout(); + wtime = 4*atoulong(nsvc_other); + + while (1) { + for (i=len; i>0;) + if (kill(pids[--i],0) && errno != EPERM) + pids[i] = pids[--len]; + if (len==0) _exit(0); + if (wtime--==0) _exit(1); + nano_sleep(0,250000000); + } +} + +static int try_srv(char *s, char mode) { + int r; + char *save = nsvc_other; + if (mode == 'r') + nsvc_other = (respmode) ? "c" : 0; /* must be odd char !!! */ + r = tryservice(s, mode); + nsvc_other = save; + return r; +} + +static void get_timestamp() { + char *x = nsvc_other; + unsigned int now; + if (x[-1] == 'C') { + if (x[0] == '+') ++x; + else return; + } + if ((now = atoulong(x))) + nsvc_other = fu(time(0) + now); +} + +int main(int argc,char *argv[]) { + int i,idx,ret=0; + pid_t pid; + char *x, **skp; + + __b_1.x = alloca(BUFFER_1_LEN); + buf = alloca(BUFFER_TMP_LEN); + mem.a = INIT_ALLOC_BUFFER; + + x = env_get("NINIT_MEMORY"); + if (x) mem.a = atoulong(x); + mem.r=mem.a; + if (mem.a==0 || mem.a > 64000 || (mem.x=alloca(mem.a))==0) _exit(1); + + errmsg_iam("nsvc"); + infd = -1; outfd = -1; + INIT_ENV_GET_HOME(initroot,"NINIT_HOME","INIT_HOME"); + + Names_skip = alloca(argc * sizeof(char *)); + for (skp=Names_skip; (x=argv[1]); argv++) { + if (x[0] != '-' || x[1] != 'S') break; + *skp++ = x+2; + } + *skp = 0; + + { + int uid=getuid(), euid=geteuid(); + if (initroot && (uid != euid)) { ops: die_xx("\ago away!"); } + if (initroot==0) initroot=INITROOT; + + if (argv[1] == 0) { setuid(uid); goto REMOVE; } + open_inout(initroot); + + if (uid != euid) { + if (setuid(uid)) goto ops; + get_services(); + close_inout(); + } + } + + nsvc_other = argv[1] + 2; + + if (argv[2]==0) { + char *a1 = argv[1]; + get_services(); + close_inout(); + + if (a1[0] == '-') { + switch (a1[1]) { + case 'V': goto REMOVE; + case 'L': + errmsg_iam(0); + while (get_name()) fmt_service(NamesI-1, 1); + e(0); + case 'H': + dumphistory(); + e(0); + case 'D': + msg("memory usage: ",fu(mem.l + root_names_len)," = ", + fu(mem.l),"+",fu(root_names_len)," = services+names [", + fu(maxprocess+1),"]"); + e(0); + } + } + + i=__findservice(a1); + if (i==-1) { print_pid(a1, -1); e(1); } + ret=fmt_service(i,0); + + if (i >= 0 && tty && root[i].pid > 1) { + INIT_ARGS2(argv, "./sys/procfs", fu(root[i].pid)); + goto PROCFS; + } + } else { + char *x; + unsigned int sig=0; + + x = argv[2]; + + if (argv[1][0]=='-') { + char flagdown=1, try_flag='r'; + respmode = 0; + + switch (argv[1][1]) { + case 'P': + ret=try_srv(x, 'P'); + if (ret) carp("Could not set PID of service ",x); + break; + + case 'D': dumpdependencies(x,0); break; + case 'E': + case 'Z': + REMOVE: + argv[0] = "./sys/remove"; /* XXX: make sys as environ! */ + PROCFS: + close_inout(); + buffer_flush(buffer_1); + ret = chdir(initroot); + if (!ret) ret=execve(argv[0], argv, environ); + break; + default: + + if (argv[3] == 0 && !str_diff(argv[2], "ALL")) { + get_services(); + argc = maxprocess + 4; + } else { + NamesX = argv + 2; + NamesI--; + } + + switch (argv[1][1]) { + case 'W': + wait_childs(argc); + case 'g': + while ((x=get_name())) { + pid=__readpid(x,1); + if (pid > 1) { errmsg_iam(0); msg(fu(pid)); } + else ret = 1; + } + break; + case 'u': respmode=1; + case 'o': + try_flag='s'; + goto try_it; + + case 'C': try_flag='c'; /* cron */ + case 'R': respmode=1; + + try_it: + case 'r': flagdown=0; + case 'd': + get_timestamp(); + while ((x=get_name())) { + idx=try_srv(x, try_flag); + if (idx==0) { + if (try_flag=='s') idx=try_srv(x,'r'); + else if (flagdown) { + pid=__readpid(x,0); + if (pid>1 && 0==kill(pid,SIGTERM)) kill(pid,SIGCONT); + } + } + if (idx) { print_pid(x,-1); ret=1; } + } + break; + + default: +#ifdef NSVC_SIGNAL_CODED + { + unsigned char *S, *Sig = (unsigned char *)NSVC_SIGNAL_CODED; + for (S=Sig; *S; S += 2) + if (argv[1][1] == *S) { sig = S[1]; break; } + } +#else +#define kk(C,S) case C: sig=S; break + kk('t',SIGTERM); kk('a',SIGALRM); kk('p',SIGSTOP); kk('c',SIGCONT); + kk('h',SIGHUP); kk('i',SIGINT); kk('k',SIGKILL); +#endif + } /* inner switch */ + } /* outer switch */ + } + + if (sig) { + while ((x=get_name())) { + pid=__readpid(x,1); + if (pid < 2) + ret=1; + else if (kill(pid,sig)) { + char* s; + switch (errno) { + case EINVAL: s="invalid signal"; break; + case EPERM: s="permission denied"; break; + case ESRCH: s="no such pid"; break; + default: s="unknown error"; + } + carp(x,": could not send signal ",fu(sig)," to PID ",fu(pid),": ",s); + ret=1; + } + } + } + } + e(ret); + return 0; +} diff --git a/nsvc_buffer.h b/nsvc_buffer.h new file mode 100644 index 0000000..6a73158 --- /dev/null +++ b/nsvc_buffer.h @@ -0,0 +1,19 @@ +#include "djb/buffer.h" + +#undef msg +#define msg(...) err_b(buffer_1,__VA_ARGS__,0) + +#define BUFFER_1_LEN 3200 +buffer __b_1 = BUFFER_INIT(write, 1, 0, BUFFER_1_LEN); +buffer *buffer_1 = &__b_1; + +static void outs(const char *X) { buffer_puts(buffer_1, X); } +static void outc(char X) { buffer_putc(buffer_1, X); } + +static void fmt_color(char *src,char color,char *suffix) { + char ops[] = "[1;39m"; ops[5]=color; + outs(ops); ops[2]='0'; ops[5]='9'; + outs(src); + outs(ops); + outs(suffix); +} diff --git a/nsvc_help b/nsvc_help new file mode 100644 index 0000000..e1eeb0d --- /dev/null +++ b/nsvc_help @@ -0,0 +1,23 @@ +usage: nsvc [-Sservice] -[uodpchaitkgrWRDHLCEZV] service(s) + nsvc -Ppid service + -u up start service with respawn; also -un + -o once start service without respawn; also -on + -d down set respawn off, stop service + -R|r respawn set on|off + -p pause send SIGSTOP + -c cont send SIGCONT + -h hangup send SIGHUP + -a alarm send SIGALRM + -i intr send SIGINT + -t term send SIGTERM + -k kill send SIGKILL + -g get output just the PID + -Z Zero free service; also -Zn + -E update ninit environ; also -En + -D list dependencies + -Wn wait n secs service to finish + -H print last n services + -L list services + -Ctime set CRON of service; also -C+time + -Ppid set PID of service + -Ssrv skip service diff --git a/open_inout.h b/open_inout.h new file mode 100644 index 0000000..1a8a61b --- /dev/null +++ b/open_inout.h @@ -0,0 +1,43 @@ +#include <sys/file.h> +#define NANO_wait \ + if (nsec < 500000000) nsec *= 2;\ + else carp("could not acquire lock on: ",home,"/in");\ + nano_sleep(0,nsec) + +static void open_inout(char *home) { + char *x,*y; + uint32t nsec = 3906249; + int len=str_len(home); + + x=alloca(len+6); if (x==0) _exit(1); + y=x+len; + while (len--) x[len] = home[len]; + + y[0]='/'; y[1]='i'; y[2]='n'; y[3]=0; + infd = open(x, O_WRONLY); + + y[1]='o'; y[2]='u'; y[3]='t'; y[4]=0; + outfd = open(x, O_RDONLY); + + if (infd<0 || outfd<0) die(1, "could not open ",home,"/[in|out]"); + +#ifdef HAVE__NR_flock + while (flock(infd, LOCK_EX | LOCK_NB)) { NANO_wait; } +#else + +#ifndef INIT_SYSTEM + while (lockf(infd, F_LOCKW, 1)) { NANO_wait; } +#else + { + struct flock fl; + byte_zero(&fl, sizeof(fl)); + fl.l_whence=SEEK_CUR; + fl.l_len = 1; + fl.l_type = F_WRLCK; + while (fcntl(infd, F_SETLKW, &fl)) { NANO_wait; } + } +#endif +#endif +} + +#undef NANO_wait @@ -0,0 +1,345 @@ +#define INIT_PROGRAM +#include "ninit.h" + +/* load a service into the process data structure and return index or -1 + * if failed */ +static int loadservice(char *s) { + struct process tmp; + int fd; + if (*s==0 || *s=='#') return -1; + fd=findservice(s); + if (fd>=0) return fd; + if (chdir(initroot) || chdir(s)) return -1; +#ifdef INIT_CREATE_INOUT_PIPE + if (SYS_mknod("log/in",S_IFIFO|0600,0)==0) symlink("log/in","out"); +#endif + byte_zero(&tmp, sizeof(tmp)); + tmp.startedat = time(0); + tmp.pr_respawn = (access("respawn", R_OK)==0); + return addprocess(&tmp, s); +} + +static void childhandler(); +static int do_poll(struct pollfd *pfd, int timeout) { + int k, n = timeout & 3; + for (k=0; k<n; k++) { + pfd[k].events = POLLIN; + pfd[k].revents = 0; + } + CHILD_UNBLOCK; + k=poll(pfd,n,timeout); + CHILD_BLOCK; + if (k<0) { + if (errno==EINTR) childhandler(); +#ifdef INIT_POLL_FAILED + else { write(1,"poll failed!\n",13); sulogin(); } +#endif + } + return k; +} + +static int startbyind(int service, int father) { + struct process *pr = root + service; + char *name = process_name(pr); + pid_t pid; + struct timespec req = {0,500000000}; + + if (pr->pid || pr->pr_circular) return service; + pr->pr_circular=1; + pr->father=father; + pr->cron=0; +#if INIT_HISTORY > 0 + for (pid = INIT_HISTORY; pid>1; --pid) history[pid] = history[pid-1]; + history[1]=service+1; +#endif + if (chdir(initroot)) return -1; + while ((pid=fork()) < 0) nanosleep(&req,0); + if (pid==0) { + CHILD_UNBLOCK; + if (chdir(initsysdir)==0) { + char *aa[5]; + INIT_ARGS5(aa, pr->pr_end ? "end" : "./run",name,initroot,initsysdir,0); + if (time(0) == pr->startedat) nanosleep(&req,0); + free_execve("./run",aa,environ); + } + _exit(1); + } + pr->pid=pid; + pr->startedat=time(0); + if (chdir(name)==0) { + int fd; + if (pr->pr_end) pr->pr_end = 0; + else pr->pr_end = (access("end",X_OK)==0); + + if ((fd=open("sync", O_RDONLY)) >= 0) { + struct pollfd pfd[2]; + unsigned int u; + byte_zero(pfd, sizeof(pfd)); + read(fd, pfd, sizeof(pfd)-1); + close(fd); + + if ((u=atoulong((void *)pfd)) == 0) u = -1; + pfd->fd = -1; + do { + do_poll(pfd, 1001); /* must be 4k+1 */ + if (pr->pid < 2) break; + } while (u--); + } + } + return service; +} + +static int startbyname(char *name,int father) { + char *s; + int fd,len,service=loadservice(name); + if (service<0) return -1; + name = root_name(service); +#ifdef INIT_BLACK + if (father>=0) + for (len=1; (s=Argv[len]); len++) + if (*s=='#' && !str_diff(s+1,name)) + return service; +#endif +#ifdef INIT_LOG_SERVICE + len = str_len(name); + s = alloca(len+5); if (s==0) return -1; + byte_copy(s,len,name); + byte_copy(s+len,5,"/log"); + startbyname(s,service); +#endif + + if (chdir(initroot) || chdir(name)) return -1; + if ((fd = open("depends", O_RDONLY)) >= 0) { + char *p, exitasapl=0; + if (GLOBAL_READ(fd,s, len,32000)) { close(fd); return 0; } + close(fd); + s[len]=0; + for (p=s; ;p=++s) { + while (*s && *s!='\n') s++; + if (*s==0) ++exitasapl; + *s=0; + startbyname(p,service); + if (exitasapl) break; + } + } + return startbyind(service,father); +} + +/* return -1 on error */ +static int restartservice(char *s) { + int n=loadservice(s); + if (n>=0 && root[n].pid<2) { + if (start_time) root[n].cron = start_time; + else { + root[n].pid=0; + circsweep(); + n=startbyname(s,-1); + } + } + start_time = 0; + return n; +} + +static void handlekilled(int ind) { + struct process *pr = root + ind; + next_cron = 0; + pr->pr_finish = 1; + pr->pid = 0; + if (pr->pr_end || pr->pr_respawn) { + circsweep(); + startbyind(ind,pr->father); + } else { + pr->startedat=time(0); + pr->pid += 1; + } +} + +static void childhandler() { + int ind; + pid_t pid; + if (do_update) return; + while ((pid=waitpid(-1,0,WNOHANG))) { + if (pid < 0) { +#ifdef INIT_EXIT_WARNING + static char saidso; + if (!saidso) { write(2,"all services exited.\n",21); ++saidso; } +#endif + return; + } + for (ind=0; ind<=maxprocess; ind++) + if (root[ind].pid==pid) { + handlekilled(ind); + break; + } + } +} + +static void do_initctl(struct pollfd *pfd) { + int fd; + if (restartservice("sysvinit") >= 0) { + if ((fd=open(INIT_FIFO,O_RDWR)) >= 0) + initctl=fd; + } else ++initctl; + pfd[1].fd = initctl; + fcntl(pfd[1].fd,F_SETFD,FD_CLOEXEC); +} + +static void read_infd() { + char *b1, *other, *buf; + struct process *pr; + int idx, len, offset; + uint32t u32; + + buf = read_alloca(384); + if (buf==0 || (len=read(infd,buf,380)) <2) return; + + b1 = buf + 1; + buf[len] = 0; buf[len+1] = 0; + offset = str_len(buf) + 1; + other = buf + offset; + u32 = atoulong(other); + next_cron = 0; + + switch (buf[0]) { + case 'D': + if (*b1=='M') t_write(mem.x,mem.a); + else { + if (*b1=='1') do_update = 1; + t_write(mem.x+mem.r, mem.a-mem.r); /* names + history */ + t_write(root, mem.l); /* precess */ + } + break; + case 'U': /* U\0argv[0] or Uservice\0 */ + if (*b1==0) { + char *aa[3]; INIT_ARGS3(aa, other, "", 0); + execve(other,aa,environ); + } else + if (len >= offset + PROCESS_SIZE && + addprocess(other,b1) >= 0) goto ok; + goto error; + case 's': + start_time = u32; + if (restartservice(b1) < 0) goto error; +ok: t_write("1",1); break; +error: t_write("0",1); break; + + default: + if ((idx=findservice(b1)) <0) goto error; + pr = root + idx; + + switch(buf[0]) { + case 'r': pr->pr_respawn = (other[0] != 0); goto write_pr; + case 'P': + if ((pid_t)u32<2 || kill(u32,0)) goto error; + pr->pid = u32; goto write_pr; + case 'c': pr->cron = u32; + case 'p': +write_pr: + t_write(pr, sizeof(struct process)); + } + } +} + +int main(int argc, char *argv[]) { + struct pollfd pfd[12]; + time_t now; + int i; +#ifdef INIT_BLACK + Argv=argv; +#endif + mem.r = INIT_ALLOC_BUFFER; + for (i=1; i<argc; i++) + if (argv[i][0]=='-') { + char *p = argv[i]+2; + switch (p[-1]) { + case 'M': mem.r = atoulong(p); break; +#ifdef INIT_HOME + case 'H': initroot = p; break; + case 'S': initsysdir = p; break; +#endif + default: p[-2] = '#'; /* -sshd --> #sshd */ + } + } + + mem.r &= 0xfff8; /* max 64K */ + mem.a = mem.r + (INIT_HISTORY+1) * sizeof(unsigned short); + mem.x = alloca(mem.a); /* if it fails bummer */ + history = mem.x + mem.r; + byte_zero(history, (INIT_HISTORY+1) * sizeof(unsigned short)); + ((unsigned char*)history)[1] = INIT_HISTORY; + + if (getpid()==1) { + set_reboot(0); + i = open("/dev/console",O_RDWR|O_NOCTTY); + if (i>0) { dup2(i,0); close(i); } + ioctl(0, KDSIGACCEPT, SIGWINCH); + } + + set_sa(SIGCHLD); + set_sa(SIGINT); /* ctrl-alt-del */ + set_sa(SIGWINCH); /* keyboard request */ +#ifdef INIT_SYSVINIT_SIGNALS + set_sa(SIGPWR); /* ifdef INIT_POWERSTATUS start powerZ */ + set_sa(SIGHUP); /* ifdef INIT_SIGHUP start levelU */ + set_sa(SIGUSR1); /* ifdef INIT_SIGUSR1 reopen /dev/initctl */ +#endif + CHILD_BLOCK; + + if (chdir(initroot) || + (infd=open("in",O_RDWR)) < 0 || + (outfd=open("out",O_RDWR|O_NONBLOCK)) < 0) { +#ifdef INIT_PIPES_ERROR + write(1,"pipes error\n",12); sulogin(); +#endif + } else { + int fd=open(".sync", O_RDONLY); + while ((i=read(fd,pfd,sizeof(pfd))) > 0) write(1,pfd,i); + close(fd); + } + + fcntl(infd,F_SETFD,FD_CLOEXEC); + fcntl(outfd,F_SETFD,FD_CLOEXEC); + + if (argv[argc-1][0] == 0) { + ++do_update; + t_write("8",1); + } else { + for (i=1; i<argc; i++) restartservice(argv[i]); + if (maxprocess < 0) restartservice("default"); + } + + pfd[0].fd = infd; + pfd[1].fd = -1; + + for (;;) { + for (i=0; i<4; i++) + if (got_sig[i]) { + char *xx = NINIT_SERVICES_CODED; + got_sig[i]=0; restartservice(xx + xx[i]); + } + childhandler(); + + if ((time(&now)) > next_cron) { + time_t t; next_cron = now + 1800; + for (i=0; i<=maxprocess; i++) { + struct process *pr = root + i; + if (pr->pid > 1 && kill(pr->pid, 0)) handlekilled(i); + + if (pr->pid < 2 && (t=pr->cron) > 0) { + if (t < now) restartservice(root_name(i)); + if (t < next_cron) next_cron = t; + } + } + } + + if ((i=do_poll(pfd, 5002)) == 0) { /* timeout; must be 4k+2 */ + INIT_FREE_MEMBLOCKS(do_update=0); + if (initctl < -1) do_initctl(pfd); + continue; + } + if (i>0) { + if (pfd[0].revents) read_infd(); + if (pfd[1].revents) restartservice("sysvinit"); + } + } +} diff --git a/pidfile.c b/pidfile.c new file mode 100644 index 0000000..d8e14e6 --- /dev/null +++ b/pidfile.c @@ -0,0 +1,65 @@ +#include <unistd.h> +#include <errno.h> +#include <alloca.h> +#include <fcntl.h> +#include "ninitfeatures.h" +#include "process_defs.h" + +static int infd, outfd; + +#include "open_inout.h" +#include "tryservice.h" + +int main(int argc, char* argv[]) { + char *x, *initroot, **arg; + struct process pr[6]; + unsigned long pidfile; + int count=0, pid, ret=1; + + if (argc<4) die(1, + "usage: ninit-pidfile", + " service /var/run/daemon.pid [-H home] /sbin/daemon ..."); + errmsg_iam("ninit-pidfile"); + + if (unlink(argv[2]) && errno != ENOENT) + die(1, "could not remove pid file: ", argv[2]); + + arg = argv + 3; + x = arg[0]; + + if (argc > 5 && x[0] =='-' && x[1] =='H' && x[2] ==0) { + initroot = arg[1]; + arg += 2; + } else + initroot = INITROOT; + + while ((pid = fork()) < 0) nano_sleep(0, 500000000); /* 0.5 sec */ + + if (pid == 0) { + x = arg[0]; + + arg[0] = x + str_rchr(x,'/'); + if (arg[0]) arg[0]++; + else arg[0]=x; + + execve(x,arg,environ); + die(3, "execve failed on: ", x); + } + + while (1) { + if (read_ulongs(argv[2], &pidfile, 1)) { + if (str_len(argv[1]) > 320) ret=1; + else { + ret = tryservice(initroot,argv[1],"P",fu(pidfile), pr); + ret = (ret != sizeof(pr[0]) || pr->pid != (pid_t)pidfile); + } + break; + } + if (++count>=30) break; + else + nano_sleep(1, 0); + } + + if (ret) carp("could not set PID of service ", argv[1]); + return ret; +} diff --git a/printf.c b/printf.c new file mode 100644 index 0000000..1d14e54 --- /dev/null +++ b/printf.c @@ -0,0 +1,99 @@ +#include <unistd.h> +#include <errno.h> + +struct mini_buffer { + char *x; + unsigned int p, n; + int fd; +}; + +static char buf_space[512]; +struct mini_buffer b = { buf_space, 0, sizeof(buf_space), 1 }; + +static void s_write(int fd, char *s, int n) { + int w; + while (n) { + w = write(fd,s,n); + if (w==0) _exit(1); + if (w==-1) { + if (errno == EINTR) continue; + _exit(1); + } + s += w; + n -= w; + } +} + +void out_flush() { s_write(b.fd, b.x, b.p); b.p=0; } +void out_char(char ch) { if (b.p==b.n) out_flush(); b.x[b.p] = ch; b.p++; } +void outs(char *s) { while (*s) { out_char(*s); ++s; } } + +static void bad(char *fmt, char *s) { + if (b.fd==1) out_flush(); + b.fd=2; + outs("\nbad format: "); outs(fmt); outs("\nstart: "); + outs(s); outs("\n"); out_flush(); _exit(2); +} + +char *conv_esc(char *x, char *pr_char) { + char *e0 = "ntrabfvEe\\"; + char *e1 = "\n\t\r\a\b\f\v\033\033\\"; + char ch; + int k; + for (k=0; k<10; k++) + if (e0[k] == *x) + { *pr_char = e1[k]; return x; } + + for (k=0, ch=0; '0'<=*x && *x<'8' && k<3; k++, x++) + ch = ch*8 + (*x-'0'); + if (k == 0) return 0; + *pr_char = ch; + return --x; +} + +int main(int argc, char **argv) { + char *fmt, *s, *x, ch; + if (argc<2) _exit(100); + fmt = argv[1]; + argv += 2; + + for (s=fmt; (ch=*s); s++) { + if (ch != '%' && ch != '\\') goto print_char; + if ((ch = *++s) == 0) goto bad_fmt; + + if (s[-1] == '\\') { + if ((x=conv_esc(s,&ch)) == 0) goto bad_fmt; + s = x; + print_char: + out_char(ch); + } else { /* % */ + switch (ch) { + case '%': goto print_char; + case 's': + case 'b': + if ((x=*argv++)) { + if (ch=='s') outs(x); + else { /* %b */ + char *y, *tmp; + for (tmp=x; (ch=*x); x++) { + if (ch == '\\') { + if ((y=conv_esc(++x,&ch)) == 0) bad(tmp, x-1); + x = y; + } + out_char(ch); + } + } + break; + } + out_flush(); b.fd=2; + outs("\nmissing argument"); + default: + bad_fmt: + bad(fmt,s-1); + } + } + } + out_flush(); + fsync(1); + _exit(close(1)); +} diff --git a/procfs.c b/procfs.c new file mode 100644 index 0000000..a48e074 --- /dev/null +++ b/procfs.c @@ -0,0 +1,84 @@ +#include <fcntl.h> +#include <unistd.h> +#include <alloca.h> +#include "ninitfeatures.h" +#include "nsvc_buffer.h" + +static buffer b = BUFFER_INIT(read, 0, 0, BUFFER_TMP_LEN); + +static void print_procfs(char *pidnum) { + char *x, *qq[8], *buf = b.x; + int fd,k; + unsigned char ch; + + if (chdir("/proc/") || chdir(pidnum)) return; + + INIT_ARGS4(qq, "cmdline","environ","status","statm"); + for (k=0; k<4; k++) { + x = qq[k]; + + fd = open(x, O_RDONLY); + if (fd>=0) { + b.fd = fd; + fmt_color(x,'5',":"); + + if (k==2) { + int got=0, ok_line=0; + char first[24]; + + msg("\tcat /proc/", pidnum, "/status"); + while (buffer_getc(&b, (char *)&ch)>0) { + if (got<3) { first[got++]=ch; continue; } + if (ok_line) outc(ch); + if (ch=='\n') { got=0; ok_line=0; continue; } + + if (got>3) continue; + if (!str_diffn(first,"Uid",3) || + !str_diffn(first,"Gid",3) || + !str_diffn(first,"Gro",3) || + !str_diffn(first,"Sta",3)) ok_line=1; + first[got]=ch; + first[++got]=0; + if (ok_line) outs(first); + } + } else { /* k=0,1 */ + outc('\n'); + while (buffer_getc(&b, (char *)&ch) >0) { + switch (ch) { + case 0: msg("\260"); break; + case 1: ch=':'; + default: + if (ch != '\n' && (ch < 32 || ch > 127)) { + x = fu(ch); *--x = '.'; + fmt_color(x,'1',""); + } + else outc(ch); + } + } + } + close(fd); + } + } + + INIT_ARGS3(qq, "exe","cwd","root"); + for (fd=0; fd<3; fd++) { + x = qq[fd]; + k = readlink(x, buf, BUFFER_TMP_LEN); + if (k>0 && k < BUFFER_TMP_LEN) { + buf[k] = 0; + fmt_color(x,'5',":\t"); + msg(buf); + } + } +} + +int main(int argc, char **argv) { + if (argc>1) { + __b_1.x = alloca(BUFFER_1_LEN); + b.x = alloca(BUFFER_TMP_LEN); + + print_procfs(argv[1]); + buffer_flush(&__b_1); + } + return 0; +} diff --git a/pututmpid.c b/pututmpid.c new file mode 100644 index 0000000..84492c1 --- /dev/null +++ b/pututmpid.c @@ -0,0 +1,142 @@ +/* pututmpid.c + + usage: pututmpid [-w] c2 child arg... + usage: pututmpid reboot + usage: pututmpid halt + + c2 is the same entry as in /etc/inittab + c2:2345:respawn:/sbin/fgetty tty2 + see the end of this file how it works +*/ + +#include <unistd.h> +#include <fcntl.h> +#include <utmp.h> +#include <time.h> +#include <sys/utsname.h> +#include "ninitfeatures.h" +#include "utmp_defs.h" + +int main(int argc, char **argv) { + struct utmp u; + char *utid,*argv0,*x; + char flagwtmp=0; + int fd; + off_t pos=0; + + if (argv[1] && argv[1][0] == '-' && argv[1][1] == 'w') + {++argv; --argc; flagwtmp=1;} + + if (argc >=3) { + char **e, *env[2] = {0,0}; + size_t len = str_len(argv[1]); + utid = argv[1]; + if (len>4) utid += len-4; + argv += 2; + + fd=open(_PATH_UTMP, O_RDWR); + while (utmp_io(fd, &u, F_RDLCK)) { + if (!str_diffn(u.ut_id, utid, sizeof(u.ut_id))) { + if (u.ut_type == USER_PROCESS) { + u.ut_tv.tv_sec=time(0); + u.ut_type=DEAD_PROCESS; + /* byte_zero(&u.ut_user, sizeof(u.ut_user)); + byte_zero(&u.ut_host, sizeof(u.ut_host)); */ + do_wtmp(&u); + } + break ; + } + pos += sizeof(struct utmp); + } + + byte_zero(&u,sizeof(u)); + str_copyn(u.ut_id, utid, sizeof(u.ut_id)); + u.ut_pid=getpid(); + u.ut_tv.tv_sec=time(0); + u.ut_type=INIT_PROCESS; + + if (fd>=0 && lseek(fd,pos,SEEK_SET) == pos) + utmp_io(fd,&u,F_WRLCK); + close(fd); + + if (flagwtmp) do_wtmp(&u); + + argv0 = argv[0]; + x = argv[0]; + x += str_rchr(x,'/'); + if (x[0]) argv[0] = x+1; + else argv[0] = argv0; + + for (e=environ; *e; e++) + if (!str_diffn(*e,"TERM=",5)) {*env=*e; break;} + + execve(argv0, argv, env); + write(2,"unable to exec: ",16); + write(2,argv0,str_len(argv0)); + write(2,"\n",1); + return(100); + } + + /******************************************************/ + if (argc == 2) { + struct utsname uname_buf; + fd = -1; + switch (argv[1][0]) { + case 'r': + fd=open(_PATH_UTMP, O_RDWR); + while (utmp_io(fd, &u, F_RDLCK)) { + /* if already exist do nothing */ + if (u.ut_type == BOOT_TIME) { close(fd); return 111; } + pos += sizeof(struct utmp); + } + + byte_zero(&u,sizeof(u)); + str_copy(u.ut_user,"reboot"); + str_copy(u.ut_line,"~"); + u.ut_type=BOOT_TIME; + break; + case 's': + case 'h': + str_copy(u.ut_user,"shutdown"); + u.ut_type=RUN_LVL; + str_copy(u.ut_line,"~~"); + break; + default: + goto usage; + } + + str_copy(u.ut_id,"~~"); + u.ut_pid=0; + u.ut_tv.tv_sec=time(0); + + /* Put the OS version in place of the hostname */ + if (uname(&uname_buf) == 0) + str_copyn(u.ut_host, uname_buf.release, 32); /* XXX overflow ? */ + + if (fd>=0 && lseek(fd,pos,SEEK_SET) == pos) + utmp_io(fd,&u,F_WRLCK); + close(fd); + + do_wtmp(&u); + return(0); + } + + usage: + write(2,"usage: pututmpid [-w] ut_id child arg...\n\ + pututmpid reboot\n\ + pututmpid halt\n",87); + return(100); +} + +/* + pututmpid: + if exist an entry in utmp with: ut_id=c2 ut_type=USER_PROCESS + then put: ut_id=c2 ut_type=DEAD_PROCESS in wtmp + + always put: ut_id=c2 ut_type=INIT_PROCESS in utmp + if -w flag put: ut_id=c2 ut_type=INIT_PROCESS in wtmp + + getty and login chanegs /var/run/utmp: + getty: ut_id=c2 ut_type=LOGIN_PROCESS + login: ut_id=c2 ut_type=USER_PROCESS +*/ diff --git a/reboot.c b/reboot.c new file mode 100644 index 0000000..5cfbec2 --- /dev/null +++ b/reboot.c @@ -0,0 +1,38 @@ +#include <unistd.h> +#include <sys/reboot.h> +#include "ninitfeatures.h" +#include "uid.h" + +#define USAGE "ninit-reboot: Aborted.\nSay \"ninit-reboot (RESTART|ENABLE_CAD|DISABLE_CAD|HALT|POWER_OFF)\" if you really mean it.\n" + +void usage(void) { + write(2, USAGE, str_len(USAGE)); + _exit(1); +} + +int main(int argc, char *argv[]) { + unsigned int m=0; + if (argc!=2) + usage(); + + sync(); + sync(); + sync(); + nano_sleep(1, 0); + + if (!str_diff(argv[1], "RESTART")) m=RB_AUTOBOOT; + else if (!str_diff(argv[1], "HALT")) m=RB_HALT_SYSTEM; + else if (!str_diff(argv[1], "ENABLE_CAD")) m=RB_ENABLE_CAD; + else if (!str_diff(argv[1], "DISABLE_CAD")) m=RB_DISABLE_CAD; + else if (!str_diff(argv[1], "POWER_OFF")) m=RB_POWER_OFF; + else usage(); + + set_reboot(m); + set_reboot(RB_HALT_SYSTEM); + + close(0); + close(1); + close(2); + + while(1) nano_sleep(10,0); +} diff --git a/reload.c b/reload.c new file mode 100644 index 0000000..7d6821a --- /dev/null +++ b/reload.c @@ -0,0 +1,321 @@ +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/poll.h> +#include <limits.h> +#include "ninit.h" + +#define USAGE "Usage:\n" \ +"\tninit-reload ","-v","\n" \ +"\tninit-reload ","-m > dump_memory_file\n" \ +"\tninit-reload ","-d > dump_data_file\n" \ +"\tninit-reload ","[Options] /path/to/ninit [arg(s)...]\n", \ +"\nOptions:\n\t[-t time_diff]\t[-f data_file]\t" \ +"[-u]\t\t[-v]\n\t" \ +"[-R service]\t[-r number]\t[-a auto-size]\n\t" \ +"[-E file]\t[-e var=name]\t[-e variable]\t[-e -]\n" + +#define UNKNOWN_PROCESS_SIZE + +static char *buf, *flag_file; +static unsigned int verbose; +static char do_update, get_memory, get_data; + +#define UL sizeof(uint32t) + +void die_xx(char *s) { errmsg_iam("ninit-reload"); err(2,s,0); _exit(1); } + +static int safe_read_code(char code) { + int r, k; + for (k=0; k<50; k++) { + r = read(outfd,buf,BUFFER_TMP_LEN); + if (r == 1 && buf[0] == code) return 0; + if (r <= 0) nano_sleep(0, 20000000); /* 0.020 sec */ + else break; + } + return -1; +} +static void safe_read() { + if (safe_read_code('1')) die_xx("wrong responce from ninit"); +} +static void safe_read_execve(char code, char *s) { + if (safe_read_code(code) == 0) return; + die(1, "Ops! I got exec error from ",s); +} +static void safe_write(int len) { + if (len != write(infd, buf, len)) die_xx("error writing to ninit"); +} +static int safe_cat(char *dest, char *src, int len) { + int k = str_len(dest); + if (k<len) k += str_copyn(dest+k, src, len-k); + dest[k] = 0; + return k; +} +static void put_arg(char *string) { + uint32t *len = (uint32t *)buf; + buf[UL] = 0; + *len = safe_cat(buf+UL, string, 300); + safe_write(*len + UL); + safe_read(); +} + +#include "check_opt.h" +#include "get_services.h" +#include "open_inout.h" + +static char *do_AutoSize(uint32t len) { + uint32t u; + char *x; + if (len>300) len=300; + u = (maxprocess + len + 8) * (PROCESS_SIZE + 12); + + x = fu(u & ~15); + *--x = 'M'; *--x = '-'; + +#ifndef INIT_TIMEOUT_WRITE + if (u > PIPE_BUF - 256) + carp("\n\a*** WARNING *** for option ",x, " ninit must be build\n" + "with INIT_TIMEOUT_WRITE flag. See ninitfeatures.h"); +#endif + return x; +} + +static char *align_name(char *s) { + static char x[20]; + int len = str_len(s); + byte_set(x,sizeof(x),' '); + if (len<=16) len=18 - len; + else { len=1; x[0] = '\t'; } + x[len] = 0; + return x; +} + +int main(int argc, char **Argv) { + char *remove_P[argc], *env_c[argc], **env=0; + char *auto_memory=0, **argv; + time_t TimeDiff=0; + int do_Remove=0, do_remove=0, remove_p[argc], AutoSize=0; + int i,j,k,env_len=0; + uint32t *len; + char *initroot, *x; + + INIT_ENV_GET_HOME(initroot,"NINIT_HOME","INIT_HOME"); + buf = alloca(BUFFER_TMP_LEN); + len = (uint32t *)buf; + + mem.a = INIT_ALLOC_BUFFER; + if (argc < 2) { usage: die(1, USAGE); } + if (initroot == 0) initroot = INITROOT; + argv=Argv; + + argv++; + errmsg_iam("ninit-reload"); + while (argv[0] && argv[0][0]=='-') { + switch(argv[0][1]) { + case 'v': verbose++; break; + case 'u': do_update=1; break; + case 'm': get_memory=1; break; + case 'd': get_data=1; break; + case 'f': chk_opt(argv,x); flag_file = x; break; + case 't': chk_opt(argv,x); TimeDiff = x_atoi(x); break; + case 'a': chk_opt(argv,x); AutoSize = x_atoi(x); break; + case 'R': chk_opt(argv,x); remove_P[do_Remove++] = x; break; + case 'e': chk_opt(argv,x); + /* next clears all like env -i! to remove '-' do; + * echo > /tmp/x; ninit-raload -E /tmp/x ... */ + if (x[0]=='-' && x[1]==0) x=""; + env_c[env_len++] = x; break; + case 'E': chk_opt(argv,x); + i=open(x, O_RDONLY); + if (i<0) die(1, "unable to open ", x); + else { + if (GLOBAL_READ(i,x, j,12000)) _exit(1); + close(i); + x[j] = 0; + + j = splitmem(0,x,'\n'); + env = alloca((argc + j + 5) * sizeof(char *)); + if (env == 0) _exit(1); + splitmem(env,x,'\n'); + skip_comments(env); + } + break; + case 'r': + chk_opt(argv,x); + if ('0'<=x[0] && x[0]<='9') remove_p[do_remove++] = x_atoi(x); + break; + default: + die(1, "Unknown Option: ",argv[0]); + } + argv++; + } + + argc -= (argv-Argv); + + x = env_get("NINIT_MEMORY"); + if (x) mem.a = atoulong(x); + mem.r=mem.a; + if (mem.a==0 || mem.a > 64000 || (mem.x=alloca(mem.a))==0) _exit(1); + + if (env==0) env=env_c; + else { + char **xx=env+1, *s; + for (k=1; (s=*xx); xx++) if (*s) env[k++] = s; + byte_copy(env+k, env_len * sizeof(char *), env_c); + env_len += k; + } + + if (flag_file==0) open_inout(initroot); + else { + if (*flag_file == 0) goto usage; + infd=-1; + outfd=open(flag_file, O_RDONLY); + if (outfd<0) die(1, "could not open ",flag_file); + process_size = lseek(outfd,0,SEEK_END); + lseek(outfd,0,SEEK_SET); + } + + errmsg_iam(0); + if (get_memory || get_data) { + struct pollfd pfd; + pfd.fd=outfd; + pfd.events=POLLIN; + buf[0] = 'D'; + buf[1] = (get_memory) ? 'M' : '1'; + write(infd,buf,2); + + for (;;) { + j=poll(&pfd,1,400); + if (j==-1) { + if (errno==EINTR) { carp("interrupt signal"); } + else die_xx("poll fialed!"); + } else if (j==1) { + i=read(outfd,buf,BUFFER_TMP_LEN); + if (i>0) write(1,buf,i); + } else { + return 0; + } + } + } + + get_services(); + + if (verbose) { + char *what; + msg("services from: ", + (flag_file) ? "" : initroot, + (flag_file) ? flag_file : "/out"); + for (j=0; j<= maxprocess; j++) { + switch (root[j].pid) { + case 1: what = "finish"; break; + case 0: what = "down"; break; + default: what = fu(root[j].pid); + } + x = root_name(j); + msg(fu(j),".\t",x,align_name(x),what); + } + if (!do_update) return 0; + } + + if (do_update) { + if (!argv || !argv[0] || argv[0][0]!='/') + die_xx("I need the full /path/of/ninit/program"); + + k = str_len(argv[0]); + if (k > 240) die_xx("too long file name. must be <= 240."); + + if (access(argv[0], X_OK)) + die(1, "Ops! Check the mode of ", argv[0]); + + if (AutoSize) auto_memory=do_AutoSize(AutoSize); + + errmsg_puts(1,"\nreplacing current ninit with: "); + fmt_argv(1,argv, " "); + msg("",auto_memory); + + if (flag_file) { + close(infd); close(outfd); + open_inout(initroot); + } + + buf[0]='U'; buf[1]='U'; buf[2]=0; + + if (argc>1 || auto_memory || env_len) { + /* ----- to ninit ----- */ + safe_cat(buf, initroot, 200); + k = safe_cat(buf, "/sys/update", 230); + if (access(buf+2, X_OK)) + die(1, "Ops! Check the mode of ", buf+2); + + buf[1] = 0; + buf[k++] = 0; + if (verbose) msg("sending reload signal to ","ninit"); + safe_write(k); + + /* ----- from/to update ----- */ + safe_read_execve('7', "~/sys/update"); + *len=argc + 1 + (auto_memory != 0); + safe_write(UL); + safe_read(); + + for (i=0; i<argc; i++) put_arg(argv[i]); /* argv */ + if (auto_memory) put_arg(auto_memory); + put_arg(""); + + *len=env_len; + safe_write(UL); + safe_read(); + for (i=0; i<env_len; i++) put_arg(env[i]); + + *len = 1953066852; + if (verbose) msg("sending reload signal to ","~/sys/update","\n"); + safe_write(UL); + } else { + k=safe_cat(buf, argv[0], 300); + buf[1] = 0; + buf[k++] = 0; + if (verbose) msg("sending reload signal to ","ninit","\n"); + safe_write(k); /* execve argv[0] */ + } + + /* ----- from/to ninit ----- */ + safe_read_execve('8',argv[0]); + if (verbose) msg("now trying to restore services:"); + + for (j=0; j<= maxprocess; j++) { + char *name=root_name(j); + + for (k=0; k<do_remove; k++) + if (j==remove_p[k]) { + if (verbose) { msg("\t",name,align_name(name),"removed"); } + k=-1; break; + } + if (k==-1) continue; + + for (k=0; k<do_Remove; k++) + if (!str_diff(remove_P[k],name)) { + if (verbose) { msg("\t",name,align_name(name),"removed"); } + k=-1; break; + } + if (k==-1) continue; + + root[j].pr_circular = 0; + root[j].startedat += TimeDiff; + buf[0]='U'; buf[1]=0; + k = 1 + safe_cat(buf, name, 300); + byte_copy(buf + k, PROCESS_SIZE, &root[j]); + k += PROCESS_SIZE; + + safe_write(k); + safe_read(); + if (verbose) { msg(fu(j),".\t",name,align_name(name),"done"); } + } + + if (verbose) errmsg_puts(1,"\n"); + msg("Done!\tTry: nsvc -L"); + return(0); + } + goto usage; + return 0; +} diff --git a/remove.c b/remove.c new file mode 100644 index 0000000..e3d0db3 --- /dev/null +++ b/remove.c @@ -0,0 +1,74 @@ +#include <unistd.h> +#include <alloca.h> +#include <fcntl.h> +#include "ninitfeatures.h" +/* + convert: xxx option A B C D + to: /sbin/ninit-reload arg(s) + and start above program + options: -V -E -Z[number] + */ +int main(int argc, char **argv) { + char *x, **qq, **q; + char *help_file = ".sync"; + char flag[3]={ '-', 'e', 0 }; + + + x = argv[1]; + if (x == 0) { help_file = ".nsvc_help"; goto write_it; } + if (x[0] != '-') _exit(1); + + qq = alloca(sizeof(char *) * (2*argc + 30)); + q = qq; + + INIT_ARGS2(q, "/sbin/ninit-reload","-u"); + q += 2; + + switch (x[1]) { + case 'Z': flag[1] = 'R'; + case 'E': + if (x[2]) { + x[1]='a'; + INIT_ARGS2(q,x,"-v"); + q += 2; + } + break; + case 'V': { + char buf[1024]; + int r, fd; + + write_it: + fd = open(help_file, O_RDONLY); + while ((r = read(fd, buf, sizeof(buf))) > 0) /* close(fd); */ + write(1, buf, r); + } + default: + _exit(0); + } + + for (argv += 2; (x=*argv); argv++) { + if (*x == 0) continue; /* skip empty args */ + INIT_ARGS2(q,flag,x); + q += 2; + } + + *q++ = "/sbin/ninit"; + INIT_ENV_GET_HOME(x,"NINIT_HOME","INIT_HOME"); + + if (x) { + x -= 2; + x[0] = '-'; + x[1]='H'; + *q++ = x; + } + *q = 0; + + carp("NINIT-remove: starting:"); + fmt_argv(1, qq, " "); + errmsg_puts(1,"\n"); + errmsg_puts(1,0); + + /* return 0; */ + execve(qq[0], qq, environ); + _exit(1); +} @@ -0,0 +1,177 @@ +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <alloca.h> +#include <sys/ioctl.h> +#include <sys/wait.h> +#include <grp.h> +#include "ninitfeatures.h" +#include "uid.h" + +static char *service, *home, *sysdir; + +static void exec_setup(char *s) { + if (access(s, X_OK) == 0) { + char *x = fu(getpid()); + pid_t pid=fork(); + if (pid==-1) return; + if (pid==0) { + char *qq[6]; + INIT_ARGS6(qq, s,service,home,sysdir,x,0); + execve(s,qq,environ); + _exit(1); + } + waitpid(pid,0,0); + } +} + +static struct error_table table[] = { + {ENOEXEC, "Exec format error"}, + {ENOENT, "No such file"}, + {EACCES, "Permission denied"}, + {ENOMEM, "Out of memory"}, + {0,0} +}; + +static void die_exec() { + char *x=0, *y = ": "; + struct error_table *t=table; + for (; t->s; t++) + if (t->n == errno) { x = t->s; break; } + if (x==0) { x = fu(errno); y = ": errno="; } + errmsg_iam(0); + carp(home,"/",sysdir,"/run",": Could not start ", + home,"/",service,"/run",y,x); + _exit(1); +} + +#define NI_TEXT_FILES 2 +#define MAX_groups 33 +enum { NI_params,NI_pidfile }; + +int main(int Argc, char **Argv) { + char **argv,*argv_0,**xx,*s; + char *tmp[10]; + static char **aa[NI_TEXT_FILES]; + static unsigned long uid[MAX_groups + 2]; + unsigned long ul[1]; + int i,fd,len; + + errmsg_iam("run"); + if (Argc<3) + { carp("usage: ",errmsg_argv0," service home sys"); _exit(1); } + + service=Argv[1]; + home= Argv[2]; + sysdir= Argv[3]; + + if (chdir(home) || chdir(service)) die_exec(); + + if (Argv[0][0] != '-') { + if (getppid() == 1) { + ioctl(0, TIOCNOTTY, 0); + setsid(); + opendevconsole(); + // ioctl(0, TIOCSCTTY, 1); + // tcsetpgrp(0, getpgrp()); + } + + if (Argv[0][0] == 'e') { /* "end" */ + execve(Argv[0],Argv,environ); + _exit(100); + } + + exec_setup("sys-rsetup"); + + if (!access("wait", R_OK) || + !access("environ", R_OK) || + !access("softlimit", R_OK) || + !access("cron", R_OK)) { + Argv[0] = "run-wait"; + + if (chdir(home) || chdir(sysdir)) return 1; + execve("./run-wait",Argv, environ); + if (chdir(home) || chdir(service)) return 1; /* exec fails; go on */ + } + } + + exec_setup("rsetup"); + + INIT_ARGS2(tmp, "params","pidfile"); + for (i=0; i < NI_TEXT_FILES; i++) { + int offset=6; + if (i) offset=0; + + if ((fd = open(tmp[i], O_RDONLY)) >=0) { + if (GLOBAL_READ(fd,s, len,12000)) _exit(1); + close(fd); + s[len]=0; + + len = splitmem(0,s,'\n'); + xx=alloca((len+offset+1) * sizeof(char*)); if (xx==0) _exit(1); + xx += offset; + aa[i] = xx; + + splitmem(xx,s,'\n'); + if (i==0 && xx[--len][0]==0) xx[len]=0; + skip_comments(xx); + } + } + + if ((xx=aa[NI_params])) argv = xx; + else { argv = tmp+7; *argv = 0; } + + for (len=129; ; len *= 2) { + argv_0=alloca(len); if (!argv_0) _exit(1); + if ((i=readlink("run",argv_0,len))<0) { + if (errno!=EINVAL) die_exec(); /* not a symbolic link */ + argv_0="./run"; + break; + } + if (i<len) { argv_0[i]=0; break; } + } + + if ((xx=aa[NI_pidfile])) { + argv -= 5; + INIT_ARGS5(argv, service, xx[0], "-H", home, argv_0); + argv_0 = "/sbin/ninit-pidfile"; + } + + s = argv_0 + str_rchr(argv_0, '/'); + if (s[0]) ++s; + else s = argv_0; + *--argv = s; + + dup2_inout("in", 0,O_RDONLY); + dup2_inout("out",1,O_WRONLY); + + if (read_ulongs("sleep",ul,1)) + nano_sleep(*ul, 200000000); + if ((s=read_header("nice"))) { + if (*s == '-') { i=-1; s++; } else i=1; + if (scan_ulong(s, ul)) { i *= (int)ul[0]; nice(i); } + } + + len = read_ulongs("uid",uid,33); +#ifdef RUN_WANT_GID_FILE + if (len < 2 && read_ulongs("gid",uid+1,1)) len=2; +#endif + + if (len > 1) { + gid__t g[len]; + for (i=0; i<len; i++) g[i] = uid[i]; + SYS_setgroups(len-1,g+1); + } + if (uid[1]) setgid(uid[1]); + if (uid[0]) setuid(uid[0]); + + exec_setup("setup"); + if (read_ulongs("alarm",ul,1)) alarm(*ul); + + for (fd=3; fd<1024; ++fd) close(fd); + + if (!access("pause", R_OK)) kill(getpid(), SIGSTOP); + execve(argv_0,argv,environ); + die_exec(); + return 1; +} diff --git a/runlevel.c b/runlevel.c new file mode 100644 index 0000000..cf9930b --- /dev/null +++ b/runlevel.c @@ -0,0 +1,137 @@ +#include <unistd.h> +#include <utmp.h> +#include <time.h> +#include <alloca.h> +#include <fcntl.h> +#include <sys/utsname.h> +#include "ninitfeatures.h" +#include "utmp_defs.h" + +static unsigned long env_free, env_allocated; +#include "contrib/put_env.h" + +static void init_utmp(struct utmp *u) { + byte_zero(u, sizeof(struct utmp)); + str_copy(u->ut_line,"~"); + str_copy(u->ut_id,"~~"); + u->ut_tv.tv_sec=time(0); +} + +int main(int argc, char **argv) { + pid_t prev=0; + int i,fd; + char **env, ch, prevlevel[20], ninit_runlevel[20]; + char boot_time=0; + struct utmp u; + struct utsname uname_buf; + off_t pos=0, runlevel_pos=0; + + str_copy(prevlevel, "PREVLEVEL=N"); + str_copy(ninit_runlevel, "NINIT_RUNLEVEL=N"); + + fd=open(_PATH_UTMP, (argc>1) ? O_RDWR : O_RDONLY); + while (utmp_io(fd, &u, F_RDLCK)) { + if (u.ut_type == BOOT_TIME) boot_time = 1; + if (u.ut_type == RUN_LVL) { + prev = u.ut_pid; + runlevel_pos = pos; + + if (argc < 2) { + char m[] = "N N\n"; + i = prev / 256; if (i) m[0] = i; + i = prev % 256; if (i) m[2] = i; + write(1, m, 4); + return 0; + } + } + pos += sizeof(struct utmp); + } + + if (argc < 2) _exit(1); + prev %= 256; + ch = argv[1][0]; + + if (boot_time == 0) { + init_utmp(&u); + u.ut_type=BOOT_TIME; + str_copy(u.ut_user,"reboot"); + if (lseek(fd,pos,SEEK_SET) == pos) + utmp_io(fd,&u,F_WRLCK); + } + + pos = runlevel_pos; + if (pos == 0 && lseek(fd,0,SEEK_SET) == 0) { + while (utmp_io(fd, &u, F_RDLCK)) { + if (u.ut_type == RUN_LVL) break; + pos += sizeof(struct utmp); + } + } + + init_utmp(&u); + u.ut_type=RUN_LVL; + str_copy(u.ut_user,"runlevel"); + if (prev==0) prev='N'; + u.ut_pid = (256*prev) + ch; + + if (lseek(fd,pos,SEEK_SET) == pos) + utmp_io(fd,&u,F_WRLCK); + close(fd); + + if (uname(&uname_buf) == 0) + str_copyn(u.ut_host, uname_buf.release, 32); /* XXX overflow ? */ + do_wtmp(&u); + + /* ------ exnivon + exeve ----- */ + if (environ==0) environ = argv+argc; + for (env=environ; *env; ++env) env_allocated++; + + env_free = argc + 12; + env=alloca((env_allocated + env_free + 1) * sizeof(char*)); + if (env==0) return -1; + byte_copy(env, (env_allocated+1)*sizeof(char *), environ); + environ = env; + + prevlevel[10] = prev; + ninit_runlevel[15] = ch; + + put_env(prevlevel); + put_env(ninit_runlevel); + put_env(ninit_runlevel+6); + put_env("INIT_VERSION=" SYSVINIT_VERSION); + put_env("CONSOLE=/dev/console"); + put_env("PATH=/bin:/usr/bin:/sbin:/usr/sbin"); + + for (i=2; i<argc; ++i) { + char *v=argv[i]; + char *nenv=0; + if (v[0]=='-') { + if (v[1]==0) { + environ[0]=0; + } else { + switch (*++v) { + case 'i': environ[0]=0; goto do_it; + case 'u': + if (v[1]) { nenv = v+1; goto do_it; } + else if (argv[++i]) { nenv = argv[i]; goto do_it; } + default: + goto ready; + } + } + } else { + if (v[str_chr(v,'=')] == 0) goto ready; + nenv = v; + } + + do_it: + if (nenv) put_env(nenv); + continue; + } + + ready: + argv += i; + if (argv[0]) { + execve(argv[0], argv, environ); + return 100; + } + return 0; +} diff --git a/scripts/conf b/scripts/conf new file mode 100755 index 0000000..b443af9 --- /dev/null +++ b/scripts/conf @@ -0,0 +1,18 @@ +#!/bin/sh + +if test "$1" = "" ; then + echo usage: $0 /dir/name + exit 100 +fi + +mkdir -m 755 $1 || exit 1 +cd $1 || exit 2 + +mkfifo -m 600 in || exit 3 +mkfifo -m 600 out || exit 4 + +ln -s /etc/ninit/sys sys || exit 5 +ln -s /etc/ninit/.sync .sync || exit 6 +ln -s /etc/ninit/.nsvc_help .nsvc_help || exit 7 + +ls -laF . diff --git a/scripts/scan b/scripts/scan new file mode 100755 index 0000000..aef0bab --- /dev/null +++ b/scripts/scan @@ -0,0 +1,34 @@ +#!/bin/sh +## *setup: $1=service S2=ninit_home $3=ninit_sys $4=pid +## end: $1=service S2=ninit_home $3=ninit_sys + +op='' +case $1 in + -u) op=u; shift; break;; + -o) op=o; shift; break;; + -d) op=d; shift; break;; +esac + +if test $# -lt 2 ; then + echo 'usage: ninit-scan [ -[uod] ] service ninit_home' + exit 1 +fi + +cd $2 || exit 2 + +if test "$1" = "" ; then + prefix='' +else + cd $1 || exit 3 + prefix=$1/ +fi + +for d in * ; do + if test -d $d -a -k $d ; then + x=$op + if test "$x" = "" ; then + test -f $d/respawn && x=u || x=o + fi + /bin/nsvc -$x $prefix$d + fi +done diff --git a/scripts/service b/scripts/service new file mode 100755 index 0000000..0255308 --- /dev/null +++ b/scripts/service @@ -0,0 +1,104 @@ +#!/bin/sh + +if test -z "$1" ; then + printf "%s\n\n" ' +usage: ninit-service [-Options] service(s) +usage: ninit-service -E service file + +Options: + -A ascii output + -C show end of lines; for cat + -L long lines; for ls + -E edit file; default editor: /bin/vi; change it with: + echo /usr/bin/emacs -nw > /etc/ninit/.editor + -H/other/home default home: /etc/ninit + +example: ninit-service `find /etc/ninit/ -type d`' + exit 1 +fi + + lsopt= +catopt= + home="/etc/ninit" +editor="/bin/vi" +cstart="\033\133\061\073\063\065\155" + cend="\033\133\060\073\063\071\155" + + +while true ; do + case $1 in + -E) shift; + [ -f $home/.editor ] && editor=`head -1 $home/.editor` + [ -z "$editor" ] && editor='/bin/vi' + test $# -ge 2 && exec $editor $home/$1/$2 + continue;; + -C*) catopt=-E ; shift; continue;; + -L*) lsopt=-l; shift; continue;; + -H*) home=`echo $1 | sed -e 's/^..//'`; shift; continue;; + -A*) cstart=""; cend=""; shift; continue;; + *) break ;; + esac +done + +while true; do + +cd $home || exit 1 +[ -z "$1" ] && exit 0 + +if ! cd $1 2>/dev/null ; then + printf "\n\n*** WARNING ***\t$cstart%s$cend is not a service\n\n" $1 + shift + continue +fi + +printf "\n\tservice: $cstart%s$cend\n" $1 + +if [ -d log -a ! -p log/in ] ; then + printf "\n*** WARNING *** %s$cstart%s$cend %s\n" \ + "you have not a FIFO " "log/in" + printf "%s\n\011%s\n\011%s\n\n" "create it with:" \ + "cd $home/$1" "mkfifo -m 600 log/in && ln -s log/in out" +fi + +ls -F $lsopt +printf "\n" + +#### links +for f in in out log run end; do + [ -e $f ] && printf "%s:\t" $f && ls -F -l $f | sed -s 's/ */ /g' +done +### + +### options +for f in respawn pause pause-wait ; do + [ -f $f ] && printf "option:\t%s\n" $f +done + +### first word +for f in nice uid gid sleep maxwait sync alarm pidfile \ + sysvinit-timeout; do + if [ -f $f ] ; then + read ans < $f + printf "%s:\t%s\n" $f $ans + fi +done + +### text files: +for f in params environ softlimit wait cron depends; do + if [ -f $f ] ; then + printf "\n$cstart%s$cend: ==>\n" $f + cat $catopt $f + printf '<==\n' + fi +done + +### dirs: +for f in depends.dir; do + if [ -d $f ] ; then + printf "\n$cstart%s$cend:\n" $f + ls -la $f + fi +done + +shift +done diff --git a/scripts/tests.sh b/scripts/tests.sh new file mode 100755 index 0000000..f07d807 --- /dev/null +++ b/scripts/tests.sh @@ -0,0 +1,126 @@ +#!/bin/sh +export PATH=/bin:/usr/bin:/sbin + +if [ "$UID" = "0" ] ; then + echo '**** WARNING **** Do not start this script as ROOT !!!' + echo 'Please, interrupt me! Otherwise I continue in 30 sec.' + sleep 30 +fi + +h=`pwd` +home=$h/home +export TIMEFORMAT=' elapsed time: %R' +export NINIT_HOME=$home + +cstart='' ; cend='' ; bad='' +tty -s 2>/dev/null +if [ $? -eq 0 ] ; then + # 30=black 31=red 32=green 33=yellow 34=blue ... 37=white + # 40=black 41=red ... backgrownd color + cstart='[1;47m[1;30m' ; cend='[0;39m'; bad='[1;44m[1;31m' +fi + +echo ' starting server' $cstart$h/ninit -H$home$cend +echo ' wait for this test more than 25 seconds' +echo ' no PANIC! the test terminates in 92 sec always' +echo + +start_time=`date +%s` + +print_env () { + if [ -f /proc/$ninit_pid/environ ] ; then + echo + echo ' '$1 $cstart \ + `./sleeprun -a4 tr '\000' ' ' < /proc/$ninit_pid/environ` $cend + fi +} + +do_it () { + X=$1; shift + echo ' starting '$cstart$@$cend' #' $X + ./sleeprun -a20 $@ + ret=$? + if [ $ret -ne 0 ] ; then + echo $bad'***** WARNING *****'$cend + echo 'Exit status of' $cstart$@$cend is $ret + sleep 3 + fi + return $ret +} + +do_it '(install HOME)' ./install-bin home < misc/HOME || exit 1 +test -f home/env/run || gzip -dc home.tar.gz | do_it '(unpack home)' tar -xv + +args="./sleeprun -a90 ./env -i NINIT_TIME=empty $h/ninit -H$home" +echo ' starting' $cstart$args$cend +$args & +ninit_pid=$! +echo ' ninit PID='$cstart$ninit_pid$cend + +do_it '(waiting the ninit to start)' sleep 1 +do_it '(list)' ./nsvc -L +time do_it '(wait 4s env)' ./nsvc -W4 env +do_it '(once)' ./nsvc -o sleep +do_it '(set respawning mode)' ./nsvc -R sleep +do_it '(list)' ./nsvc -L + +sleep 1 +do_it '(diagnostic)' ./nsvc sleep ; echo +do_it '(list)' ./nsvc -L +do_it '(list pids)' ./nsvc -g sleep default +do_it '(history)' ./nsvc -H + +echo ; echo ' reloading ninit' + +after=after-reload +do_it '' ps uwwww -p $ninit_pid ; echo +do_it '' ln -sf ninit $after + +print_env 'old ninit environ:' + +current_time=`date +%s` +args="./reload -v -a 20 -eNINIT_TIME=$current_time -e Hello=world" +args="$args -eYou_are=$USER -u $h/$after -H$home" +echo ' starting' $cstart$args$cend +time ./sleeprun -a30 $args + +print_env 'new ninit environ:' + +do_it '(sleep 4+3 sec; stopping do_update mode)' sleep 4 +do_it '' ps uwwww -p $ninit_pid ; echo +do_it '' sleep 3 + +echo +time do_it 'sync mode (max 3 sec)' ./nsvc -o S +do_it '(list)' ./nsvc -L +all=`./nsvc -L` +do_it '(remove cron flags)' ./nsvc -K0 $all +do_it '(down all services)' ./nsvc -d $all + +time do_it '(wait 1s all to finish)' ./nsvc -W1 $all +do_it '(list)' ./nsvc -L +do_it '(memory usage)' ./nsvc -D +do_it '(depends)' ./nsvc -D default + +[ -f /proc/$ninit_pid/statm ] && \ + do_it '(ninit daemon)' cat /proc/$ninit_pid/statm +do_it '(kill ninit daemon)' kill $ninit_pid +wait + +end_time=`date +%s` +./sleeprun -a4 rm -f $after + +n=`expr $end_time - $start_time` ; echo +echo ' test continues:' $cstart$n sec$cend + +echo +echo $cstart' Creating services in ./etc/ninit - Demo '$cend +do_it '(clean old ./etc/)' rm -r -f ./etc +do_it '(install ./etc/ninit/)' ./install-bin . < misc/ETC +do_it '(converter)' ./inittab /etc/inittab etc/ninit services.sh > /dev/null +do_it '(making services - demo)' ./services.sh +# do_it '' ls -F ./etc/ninit + +echo +echo Look now at $cstart./services.sh$cend and $cstart./etc/ninit/$cend. +echo diff --git a/scripts/update.sh b/scripts/update.sh new file mode 100755 index 0000000..c2ca22d --- /dev/null +++ b/scripts/update.sh @@ -0,0 +1,27 @@ +#!/bin/sh +# $1 = $(DESTDIR) + +D=$1 +[ "$D" = "/" ] && D= + +echo +echo I will try to overwrite $D/sbin/ninit +echo If PID 1 is $D/sbin/ninit I will get probably an error + +[ -w $D/sbin/ninit ] || chmod 755 $D/sbin/ninit 2>/dev/null +./install-bin $D/sbin 'c:::755:/:ninit::' && exit 0 + +echo I got an error. I suppose PID 1 is $D/sbin/ninit +echo +echo I will try to replace $D/sbin/ninit with `pwd`/ninit +echo Please wait at least 30 seconds + +./sleeprun -a10 $D/sbin/ninit-reload -d > ninit.data && \ + ./sleeprun -a5 $D/sbin/ninit-reload -f ninit.data -u `pwd`/ninit && \ + ./install-bin $D/sbin 'c:::755:/:ninit::' && \ + ./sleeprun -a8 $D/sbin/ninit-reload -u $D/sbin/ninit && \ + exit 0 + +echo 'All fails! I will try simply ./install-bin' + +./install-bin $D/sbin 'x:::755:/:ninit::' diff --git a/shutdown.c b/shutdown.c new file mode 100644 index 0000000..520acdb --- /dev/null +++ b/shutdown.c @@ -0,0 +1,303 @@ +/* + * Notes: + * - uncomment `#define USE_INIT' below if you want to use shutdown + * with ninit. If defined, shutdown will try to bring down the services + * halt (for -h or -o) or reboot (-r) before killing all other processes. + * - If you do not use ninit shutdown will bring your system down similar + * to SysV-Inits shutdown with -n + */ + +#include <sys/types.h> +#include <unistd.h> +#include <sys/reboot.h> +#include <signal.h> +#include <fcntl.h> +#include <time.h> +#include <alloca.h> +#include <sys/wait.h> +#include <errno.h> +#include <stdarg.h> +#include "ninitfeatures.h" +#include "uid.h" +#include "check_opt.h" +#define Y(...) exec_cmd(__VA_ARGS__, 0) + +#define USE_INIT + +static char *me; +static int cfg_verbose; + +void sighandler(int sig) { (void)sig; } + +static void exec_argv(char **argv) { + execve(argv[0], argv, environ); + errmsg_iam(me); + carp("execve ", argv[0]," failed"); +} + +static void exec_cmd(char *cmd, ...) { + char *argv[25], **arg=argv; /* XXX can overflow */ + const char *s; + va_list a; + pid_t pid; + + *arg++ = cmd; + va_start(a,cmd); + do { + s=va_arg(a,const char*); + *arg++ = (char *)s; + } while (s); + + while ((pid = fork()) < 0) nano_sleep(0,500000000); + if (pid == 0) { + exec_argv(argv); + _exit(0); + } else + while (pid != waitpid(-1,0,0)); /* also collect zombies */ +} + +static void deep_sleep(int t) { + time_t deedline = time(0) + t; + if (t<=0) return; + if (cfg_verbose) msg("sleeping ", fu(t), "..."); + while (1) { + nano_sleep(1,0); + if (time(0) >= deedline) break; + } +} + +static void die_xx(char *s) { errmsg_iam(me); carp(s); _exit(1); } + +#ifdef USE_INIT +#include "ninit.h" + +static int infd, outfd; +static char *buf, do_update, *nsvc_other; +static unsigned int cfg_twice; +static pid_t my_pid; + +#include "get_services.h" +#include "open_inout.h" +#undef CLEAN_SERVICE +#include "tryservice_nsvc.h" + +static void try_srv(char *service, char *type) { + if (tryservice(service, type[0])) + carp("Could not ", type, " service: ", service); +} + +void ninit_servicesDown(char **skip) { + int idx; + for (idx=0; idx<=maxprocess; idx++) { + char *what = "not running"; + pid_t pid = root[idx].pid; + char *name = root_name(idx); + + if (root[idx].pr_respawn) try_srv(name, "respawn off"); + if (root[idx].cron) { + nsvc_other = "0"; + try_srv(name, "cron off"); + nsvc_other = 0; + } + if (pid > 1) { + char **x; + for (x=skip; *x; x++) + if (!str_diff(*x, name)) { pid=my_pid; what="skipped"; break; } + + if (my_pid != pid) { + what = "done"; + if (kill(pid, SIGTERM) == 0) kill(pid, SIGCONT); + else what = "failed"; + } + } + if (cfg_verbose) msg("\t--> ", name, "\t\t", what); + } +} + +void ninit_shutdown(unsigned int twice, char **skip) { + char *x; + INIT_ENV_GET_HOME(x,"NINIT_HOME","INIT_HOME"); + if (x==0) x=INITROOT; + again: + open_inout(x); + msg("Shutting down ninit services"); + + get_services(); + ninit_servicesDown(skip); + + if (twice) { + close(infd); + close(outfd); + mem.l = 0; + mem.r = mem.a; + root = 0; + maxprocess = -1; + deep_sleep(twice); + twice = 0; + goto again; + } +} +#endif + +static void printUsage() { + carp("usage: ",me," -[rhoqvt" +#ifdef USE_INIT + "mST" +#endif + "] [-E program [arg(s)]]\n" + "\t-r:\treboot after shutdown\n" + "\t-h:\thalt after shutdown\n" + "\t-o:\tpower-off after shutdown\n" + "\t-q:\tquiet mode; ignores SIGINT signal\n" +#ifdef USE_INIT + "\t-m:\tonly shutdown the ninit part\n" +#endif + "\t-v:\tbe verbose\n" + "\t-E prog:\texecute prog after KILLALL;" + " must be last option!\n" + "\t-s secs:\tstarting delay\n" + "\t-t secs:\tdelay between SIGTERM and SIGKILL\n" +#ifdef USE_INIT + "\t-T secs:\tif secs is nonzero shutdown twice ninit part\n" + "\t-S abcd:\tskip to shutdown the service abcd\n" +#endif + ); + _exit(1); +} + +int main(int argc, char **argv) { + char *x; + unsigned int cfg_downlevel=2; /* 0:1:2 == reboot:halt:poweroff */ + unsigned int cfg_delay = 3; + static unsigned int cfg_sleep; + static int cfg_ninitonly, cfg_quiet; + static char **prog; + +#ifdef USE_INIT + static char **skip, **skp; + skip = alloca((argc+5) * sizeof(char *)); + skp = ++skip; + + mem.a = INIT_ALLOC_BUFFER; + buf = alloca(BUFFER_TMP_LEN); +#endif + + if (getuid() != 0) die_xx("You are not root, go away!"); + me = argv[0]; + if (argc<2) printUsage(); + + /* parse commandline options */ + argv++; + while (argv[0] && argv[0][0]=='-') { + char *y=argv[0] + 1; + for (; *y; y++) { + switch(*y) { + case 'q': /* ignore SIGINT */ ++cfg_quiet; break; + case 'v': /* verbose mode */ ++cfg_verbose; break; + case 'r': /* reboot */ cfg_downlevel = 0; break; + case 'h': /* halt */ cfg_downlevel = 1; break; + case 'o': /* poweroff */ cfg_downlevel = 2; break; + case 't': /* delay between SIGTERM and SIGKILL */ + chk_opt(argv,x); cfg_delay = x_atoi(x); goto again; + case 's': /* sleep before shutdown services */ + chk_opt(argv,x); cfg_sleep = x_atoi(x); goto again; +#ifdef USE_INIT + case 'm': /* exit after ninit down */ + cfg_ninitonly = 1; break; + case 'T': /* delay between two services down */ + chk_opt(argv,x); cfg_twice = x_atoi(x); goto again; + case 'S': /* skip services */ + chk_opt(argv,x); *skp++ = x; goto again; + case 'E': /* execve prog arg(s) */ + chk_opt(argv,x); prog = argv; *prog = x; goto last_option; +#endif + default: + printUsage(); + } + } + again: + argv++; + } + +#ifdef USE_INIT + last_option: + *skp = 0; + *--skip = cfg_downlevel ? "halt" : "reboot"; +#endif + + opendevconsole(); + + if (cfg_ninitonly == 0) { + switch (cfg_downlevel) { + case 0: x="reboot"; break; + case 1: x="halt"; break; + case 2: x="power-off"; + } + msg(me, "\007: System is going down for ",x); + } + sync(); + + /* catch some signals; getting killed after killing the controlling terminal + * wouldn't be such a great thing... + */ + set_sa(SIGQUIT); set_sa(SIGCHLD); set_sa(SIGHUP ); + set_sa(SIGTSTP); set_sa(SIGTTIN); set_sa(SIGTTOU); + + if (cfg_quiet) set_sa(SIGINT); + deep_sleep(cfg_sleep); + +#ifdef USE_INIT + x = env_get("NINIT_MEMORY"); + if (x) mem.a = atoulong(x); + mem.r=mem.a; + if (mem.a==0 || mem.a > 64000 || (mem.x=alloca(mem.a))==0) _exit(1); + my_pid = getpid(); + + sync(); + + ninit_shutdown(cfg_twice, skip); + if (cfg_ninitonly == 0 && prog == 0) { + msg("Starting service: ", *skip); + try_srv(*skip, "start"); + } + close(infd); + close(outfd); + sync(); + + if (cfg_ninitonly) { + if (prog) exec_argv(prog); + _exit(0); + } + deep_sleep(cfg_delay); +#endif + + /* kill all processes still left */ + sync(); + msg("Sending all processes the ", "TERM signal..."); + kill(-1, SIGTERM); + deep_sleep(cfg_delay); + + sync(); + msg("Sending all processes the ", "KILL signal..."); + kill(-1, SIGKILL); + + if (prog) { sync(); exec_argv(prog); } + sync(); + + /* maximal 20 arguments !!! */ + if (!access("/sbin/quotaoff", X_OK)) Y("/sbin/quotaoff", "-a"); + Y("/sbin/swapoff", "-a"); sync(); + Y("/bin/umount", "-a"); + Y("/bin/mount", "-o", "remount,ro", "/"); + sync(); + + /* and finally reboot, halt or power-off the system */ + switch (cfg_downlevel) { + case 0: cfg_downlevel = RB_AUTOBOOT; break; + case 1: cfg_downlevel = RB_HALT_SYSTEM; break; + case 2: cfg_downlevel = RB_POWER_OFF; + } + + set_reboot(cfg_downlevel); + return 0; +} diff --git a/sighandler.h b/sighandler.h new file mode 100644 index 0000000..6a81f6c --- /dev/null +++ b/sighandler.h @@ -0,0 +1,26 @@ +static volatile char got_sig[4]; + +void sighandler(int sig) { + if (sig == SIGCHLD) return; +#ifdef NINIT_SIGNAL_HANDLER_CODED + { + unsigned char *Sig = (unsigned char *)NINIT_SIGNAL_HANDLER_CODED; + int k; + for (k=0; k<4; k++) + if ((unsigned char)sig == Sig[k]) + { got_sig[k] = 1; return; } + } +#else + + if (sig == SIGWINCH) got_sig[0]=1; + if (sig == SIGINT) got_sig[1]=1; +#ifdef INIT_SYSVINIT_SIGNALS + if (sig == SIGPWR) got_sig[2]=1; + if (sig == SIGHUP) got_sig[3]=1; +#endif +#endif /* NINIT_SIGNAL_HANDLER_CODED */ + +#ifdef INIT_SYSVINIT_SIGNALS + if (sig == SIGUSR1) { close(initctl); initctl = -5; } +#endif +} diff --git a/softlimit.c b/softlimit.c new file mode 100644 index 0000000..fb3233f --- /dev/null +++ b/softlimit.c @@ -0,0 +1,116 @@ +#include <sys/types.h> +#include <sys/resource.h> +#include "ninitfeatures.h" + +static char *arg; + +static void doit(int resource) +{ + unsigned long u; + struct rlimit r; + + if (getrlimit(resource,&r) == -1) { + carp("g","etrlimit failed"); + return; + } + + if (arg[0]=='=' && arg[1]==0) + r.rlim_cur = r.rlim_max; + else { + if (arg[scan_ulong(arg,&u)]) { + carp("invalid line: ", arg-1); + return; + } + r.rlim_cur = u; + if (r.rlim_cur > r.rlim_max) + r.rlim_cur = r.rlim_max; + } + + if (setrlimit(resource,&r) == -1) + carp("s","etrlimit failed"); +} + +void softlimit(char **argv) /*EXTRACT_INCL*/ { + while (*argv) { + arg = argv[0] + 1; + switch(argv[0][0]) { + case 0: break; + case 'a': +#ifdef RLIMIT_AS + doit(RLIMIT_AS); +#endif +#ifdef RLIMIT_VMEM + doit(RLIMIT_VMEM); +#endif + break; + case 'c': +#ifdef RLIMIT_CORE + doit(RLIMIT_CORE); +#endif + break; + case 'd': +#ifdef RLIMIT_DATA + doit(RLIMIT_DATA); +#endif + break; + case 'f': +#ifdef RLIMIT_FSIZE + doit(RLIMIT_FSIZE); +#endif + break; + case 'l': +#ifdef RLIMIT_MEMLOCK + doit(RLIMIT_MEMLOCK); +#endif + break; + case 'm': +#ifdef RLIMIT_DATA + doit(RLIMIT_DATA); +#endif +#ifdef RLIMIT_STACK + doit(RLIMIT_STACK); +#endif +#ifdef RLIMIT_MEMLOCK + doit(RLIMIT_MEMLOCK); +#endif +#ifdef RLIMIT_VMEM + doit(RLIMIT_VMEM); +#endif +#ifdef RLIMIT_AS + doit(RLIMIT_AS); +#endif + break; + case 'o': +#ifdef RLIMIT_NOFILE + doit(RLIMIT_NOFILE); +#endif +#ifdef RLIMIT_OFILE + doit(RLIMIT_OFILE); +#endif + break; + case 'p': +#ifdef RLIMIT_NPROC + doit(RLIMIT_NPROC); +#endif + break; + case 'r': +#ifdef RLIMIT_RSS + doit(RLIMIT_RSS); +#endif + break; + case 's': +#ifdef RLIMIT_STACK + doit(RLIMIT_STACK); +#endif + break; + case 't': +#ifdef RLIMIT_CPU + doit(RLIMIT_CPU); +#endif + break; + default: + carp("invalid line: ", argv[0]); + } + argv++; + } +} diff --git a/struct_root.h b/struct_root.h new file mode 100644 index 0000000..21e3257 --- /dev/null +++ b/struct_root.h @@ -0,0 +1,33 @@ +/* + if you have problems with time define + startedat and cron bellow to be time_t instead of int32t +*/ + +union pr_flags { + struct { + char b0 : 1; + char b1 : 1; + char b2 : 1; + } b; + char ch; +}; + +#define pr_respawn pr_flags.b.b0 +#define pr_end pr_flags.b.b1 +#define pr_finish pr_flags.b.b2 + +#define INIT_ROOT_DEFINE(Process,Type) \ +struct Process {\ + Type name;\ + pid_t pid;\ + union pr_flags pr_flags;\ + char pr_circular;\ + unsigned short father;\ + int32t startedat;\ + int32t cron;\ +} + +struct memalloc { + void *x; + uint32t l,r,a; +}; diff --git a/system/Files b/system/Files new file mode 100644 index 0000000..6b1aaad --- /dev/null +++ b/system/Files @@ -0,0 +1,55 @@ +# -*-Makefile-*- +CC = gcc +CFLAGS = -Os -W -Wall + +ifeq ($(FLAG_DEBUG),no) +CCC_ = @echo ' CC $<'; +else +CCC_ = +endif + +CCC = $(CCC_) $(CC) $(CFLAGS) $(OPTIMIZATION) + +NINIT_O=fork.o waitpid.o __waitpid.o wait4.o \ + nanosleep.o time.o __time.o gettimeofday.o \ + close.o open.o getpid.o access.o execve.o ioctl.o write.o \ + dup2.o fcntl.o poll.o chdir.o kill.o read.o lseek.o mmap.o \ + munmap.o symlink.o rt_sigaction.o rt_sigprocmask.o \ + SYS_reboot.o SYS_mknod.o + +RUN_O=setuid.o setgid.o SYS_setgroups.o \ + writev.o getppid.o setsid.o \ + alarm.o __alarm.o settimer.o \ + readlink.o nice.o __nice.o getpriority.o setpriority.o + +RUN_WAIT_O=setrlimit.o getrlimit.o flock.o +NSVC_O=getuid.o geteuid.o +OTHER = unlink.o sync.o rename.o pipe.o uname.o \ + SYS_chown.o chmod.o mkdir.o umask.o fsync.o \ + __errno.o __environ.o __errno_location.o SYS_brk.o __sbrk.o + +ALL = $(NINIT_O) $(RUN_O) $(RUN_WAIT_O) $(NSVC_O) $(OTHER) + +start.o: system.a + +__%.o: ../__%.c + $(CCC) -c -o $@ $< + +start.o: start.S + $(CCC) -c -include ../features.h $< +unified.o: unified.S + $(CCC) -c -include ../features.h $< +%.o: %.S + $(CCC) -c -include ./syscalls.h $< + +SYS_%.S: + @( echo '#ifdef __NR_'$*; \ + echo 'syscall_weak('$*,SYS_$*,$*')'; \ + echo '#endif' ) > $@ +%.S: + @( echo '#ifdef __NR_'$*; \ + echo 'syscall('$*,$*')'; \ + echo '#endif' ) > $@ + +clean: + rm -rf *.o *.a SYS_*.S diff --git a/system/README b/system/README new file mode 100644 index 0000000..7fda65a --- /dev/null +++ b/system/README @@ -0,0 +1,5 @@ +This is part of dietlibc. +I wrote only Makefile, Files and *.c. +*.S are almost copy/paste. + +Nikola diff --git a/system/__alarm.c b/system/__alarm.c new file mode 100644 index 0000000..49eb8f6 --- /dev/null +++ b/system/__alarm.c @@ -0,0 +1,17 @@ +#include <asm/unistd.h> +#ifndef __NR_alarm + +#include <unistd.h> +#include <sys/time.h> + +unsigned int alarm(unsigned int seconds) { + struct itimerval old, new; + unsigned int ret; + new.it_interval.tv_usec=0; + new.it_interval.tv_sec=0; + new.it_value.tv_usec =0; + new.it_value.tv_sec =(long)seconds; + if (setitimer(ITIMER_REAL,&new,&old)==-1) return 0; + return old.it_value.tv_sec+(old.it_value.tv_usec?1:0); +} +#endif diff --git a/system/__environ.c b/system/__environ.c new file mode 100644 index 0000000..b6c6a47 --- /dev/null +++ b/system/__environ.c @@ -0,0 +1 @@ +char **environ=0; diff --git a/system/__errno.c b/system/__errno.c new file mode 100644 index 0000000..3c6cdb0 --- /dev/null +++ b/system/__errno.c @@ -0,0 +1 @@ +int errno=0; diff --git a/system/__errno_location.c b/system/__errno_location.c new file mode 100644 index 0000000..76900d3 --- /dev/null +++ b/system/__errno_location.c @@ -0,0 +1,3 @@ +extern int errno; +int *__errno_location() { return &errno; } + diff --git a/system/__nice.c b/system/__nice.c new file mode 100644 index 0000000..7898012 --- /dev/null +++ b/system/__nice.c @@ -0,0 +1,8 @@ +#include <asm/unistd.h> +#include <sys/resource.h> + +#ifndef __NR_nice +int nice(int i) { + return setpriority(PRIO_PROCESS,0,getpriority(PRIO_PROCESS,0)+i); +} +#endif diff --git a/system/__sbrk.c b/system/__sbrk.c new file mode 100644 index 0000000..df2a302 --- /dev/null +++ b/system/__sbrk.c @@ -0,0 +1,25 @@ +#include <sys/types.h> +#define N ((void *)-1) + +extern void *SYS_brk(void *x); +static void *cur = N; + +void *sbrk(ssize_t incr) { + void *t=0, *old=N; + + if (cur == N) { + again: + cur = SYS_brk(t); + if (cur == N) return cur; + } + + if (old == N) { + old = cur; + if (incr) { + t = old + incr; + goto again; + } + } + + return old; +} diff --git a/system/__time.c b/system/__time.c new file mode 100644 index 0000000..2ade864 --- /dev/null +++ b/system/__time.c @@ -0,0 +1,14 @@ +#include <asm/unistd.h> + +#ifndef __NR_time + +#include <time.h> +#include <sys/time.h> + +time_t time(time_t *foo) { + struct timeval tv; + gettimeofday(&tv,0); + if (foo) *foo=tv.tv_sec; + return tv.tv_sec; +} +#endif diff --git a/system/__waitpid.c b/system/__waitpid.c new file mode 100644 index 0000000..06f44c1 --- /dev/null +++ b/system/__waitpid.c @@ -0,0 +1,11 @@ +#include <asm/unistd.h> + +#ifndef __NR_waitpid + +#include <sys/types.h> +#include <sys/wait.h> + +pid_t waitpid(pid_t pid, int *status, int options) { + return wait4(pid, status, options, 0); +} +#endif diff --git a/system/features.h b/system/features.h new file mode 100644 index 0000000..507b5ff --- /dev/null +++ b/system/features.h @@ -0,0 +1,7 @@ +/* use __errno_location instead of errno */ +#define WANT_THREAD_SAFE + +/* on i386, Linux has an alternate syscall method since 2002/12/16 */ +/* on my Athlon XP, it is twice as fast, but it's only in kernel 2.5 */ +/* 20040118: enabling this breaks User Mode Linux! It's their fault. */ +#define WANT_SYSENTER diff --git a/system/i386/Flags b/system/i386/Flags new file mode 100644 index 0000000..77b27ee --- /dev/null +++ b/system/i386/Flags @@ -0,0 +1 @@ +OPTIMIZATION = -fomit-frame-pointer -mpreferred-stack-boundary=2 -falign-functions=1 -falign-jumps=1 -falign-loops=1 diff --git a/system/i386/Makefile b/system/i386/Makefile new file mode 100644 index 0000000..f02a48f --- /dev/null +++ b/system/i386/Makefile @@ -0,0 +1,5 @@ +include Flags +include ../Files + +system.a: unified.o unified_256.o $(ALL) __restore.o __restore_rt.o + ar cr $@ $^ diff --git a/system/i386/__restore.S b/system/i386/__restore.S new file mode 100644 index 0000000..2c7936a --- /dev/null +++ b/system/i386/__restore.S @@ -0,0 +1,12 @@ +#include "syscalls.h" + +.text +.type __restore,@function +.global __restore +.align 8 +__restore: + popl %eax + movl $__NR_sigreturn,%eax + int $0x80 + hlt /* die if syscall returns */ +.size __restore,.-__restore diff --git a/system/i386/__restore_rt.S b/system/i386/__restore_rt.S new file mode 100644 index 0000000..06bb240 --- /dev/null +++ b/system/i386/__restore_rt.S @@ -0,0 +1,9 @@ +.text +.type __restore_rt,@function +.global __restore_rt +.align 8 +__restore_rt: + movl $__NR_rt_sigreturn,%eax + int $0x80 + hlt /* die if syscall returns */ +.size __restore_rt,.-__restore_rt diff --git a/system/i386/mmap.S b/system/i386/mmap.S new file mode 100644 index 0000000..c2b375e --- /dev/null +++ b/system/i386/mmap.S @@ -0,0 +1,11 @@ +.text +.global mmap +.type mmap,@function +mmap: + mov $__NR_mmap,%al + lea 0x4(%esp,1),%edx + push %edx + call __unified_syscall + pop %ecx + ret +.size mmap,.-mmap diff --git a/system/i386/start.S b/system/i386/start.S new file mode 100644 index 0000000..762e807 --- /dev/null +++ b/system/i386/start.S @@ -0,0 +1,37 @@ +.text +.global _start +_start: + popl %ecx /* %ecx = argc */ + movl %esp,%esi /* %esi = argv */ + pushl %ecx + leal 4(%esi,%ecx,4),%eax /* %eax = envp = (4*ecx)+%esi+4 */ + + pushl %eax + pushl %esi + pushl %ecx + movl %eax,environ + +#ifdef WANT_SYSENTER + movl %eax,%edx + xorl %esi,%esi +1: + add $4,%edx + cmpl %esi,-4(%edx) + jne 1b +1: + movl (%edx),%edi + test %edi,%edi + jz 1f + addl $8,%edx + cmpl $32,%edi + jne 1b + movl -4(%edx),%edi + movl %edi,__vsyscall +1: +#endif + + call main + pushl %eax + call exit + hlt /* die now ! will ya ... */ +.size _start,.-_start diff --git a/system/i386/syscalls.h b/system/i386/syscalls.h new file mode 100644 index 0000000..41c21db --- /dev/null +++ b/system/i386/syscalls.h @@ -0,0 +1,34 @@ +#include <asm/unistd.h> + +#define syscall(name,sym) \ +.text; \ +.type sym,@function; \ +.global sym; \ +sym: \ +.ifle __NR_##name-255; \ + movb $__NR_##name,%al; \ + jmp __unified_syscall; \ +.else; \ + movw $__NR_##name,%ax; \ + jmp __unified_syscall_256; \ +.endif; \ +.Lend##sym: ; \ +.size sym,.Lend##sym-sym + +#define syscall_weak(name,wsym,sym) \ +.text; \ +.type wsym,@function; \ +.weak wsym; \ +wsym: ; \ +.type sym,@function; \ +.global sym; \ +sym: \ +.ifle __NR_##name-255; \ + movb $__NR_##name,%al; \ + jmp __unified_syscall; \ +.else; \ + movw $__NR_##name,%ax; \ + jmp __unified_syscall_256; \ +.endif; \ +.Lend##sym: ; \ +.size sym,.Lend##sym-sym diff --git a/system/i386/unified.S b/system/i386/unified.S new file mode 100644 index 0000000..82f8636 --- /dev/null +++ b/system/i386/unified.S @@ -0,0 +1,68 @@ +#ifdef WANT_SYSENTER +.data +.type __vsyscall,@object +.global __vsyscall +__vsyscall: +.Lvsyscall: +.long .Lcallint80 +#endif + +.text +.weak exit +exit: +.global _exit +.type _exit,@function +_exit: + movb $1,%al +.size _exit,.-_exit + +.global __unified_syscall +.type __unified_syscall,@function +__unified_syscall: + movzbl %al, %eax +.size __unified_syscall,.-__unified_syscall + +.global __unified_return +.type __unified_return,@function +__unified_return: + push %edi + push %esi + push %ebx + movl %esp,%edi + /* we use movl instead of pop because otherwise a signal would + destroy the stack frame and crash the program, although it + would save a few bytes. */ + movl 0x10(%edi),%ebx + movl 0x14(%edi),%ecx + movl 0x18(%edi),%edx + movl 0x1c(%edi),%esi + movl 0x20(%edi),%edi +#ifdef WANT_SYSENTER + call *.Lvsyscall /* 0xffffe000 */ +#else + int $0x80 +#endif + cmp $-124,%eax + jb .Lnoerror + neg %eax +#ifdef WANT_THREAD_SAFE + movl %eax,%ebx + call __errno_location + movl %ebx,(%eax) + orl $-1,%eax +#else + mov %eax,errno + sbb %eax,%eax # eax = eax - eax - CY = -1 +#endif +.Lnoerror: + pop %ebx + pop %esi + pop %edi + ret +.size __unified_return,.-__unified_return + +#ifdef WANT_SYSENTER +.Lcallint80: + int $0x80 + ret +#endif diff --git a/system/i386/unified_256.S b/system/i386/unified_256.S new file mode 100644 index 0000000..76436ce --- /dev/null +++ b/system/i386/unified_256.S @@ -0,0 +1,7 @@ +.text +.global __unified_syscall_256 +.type __unified_syscall_256,@function +__unified_syscall_256: + movzwl %ax,%eax + jmp __unified_return +.size __unified_syscall_256,.-__unified_syscall_256 diff --git a/system/x86_64/Flags b/system/x86_64/Flags new file mode 100644 index 0000000..af36a53 --- /dev/null +++ b/system/x86_64/Flags @@ -0,0 +1 @@ +OPTIMIZATION = diff --git a/system/x86_64/Makefile b/system/x86_64/Makefile new file mode 100644 index 0000000..6b11a00 --- /dev/null +++ b/system/x86_64/Makefile @@ -0,0 +1,5 @@ +include Flags +include ../Files + +system.a: unified.o $(ALL) __restore_rt.o + ar cr $@ $^ diff --git a/system/x86_64/__restore_rt.S b/system/x86_64/__restore_rt.S new file mode 100644 index 0000000..34a5d3f --- /dev/null +++ b/system/x86_64/__restore_rt.S @@ -0,0 +1,8 @@ +.text +.align 16 +.global __restore_rt +.type __restore_rt,@function +__restore_rt: + movq $15, %rax + syscall + hlt diff --git a/system/x86_64/gettimeofday.S b/system/x86_64/gettimeofday.S new file mode 100644 index 0000000..8c2f83b --- /dev/null +++ b/system/x86_64/gettimeofday.S @@ -0,0 +1,18 @@ +.text +.global gettimeofday +.type gettimeofday,@function +gettimeofday: + mov $0xffffffffff600000,%rax + callq *%rax + cmpq $-128, %rax + jbe 1f + negl %eax + pushq %rax + call __errno_location + popq %rcx + movl %ecx,(%rax) + orq $-1, %rax +1: + ret +.Lhere: + .size gettimeofday,.Lhere-gettimeofday diff --git a/system/x86_64/start.S b/system/x86_64/start.S new file mode 100644 index 0000000..b31b9b1 --- /dev/null +++ b/system/x86_64/start.S @@ -0,0 +1,17 @@ +.text +.global _start +_start: + popq %rdi /* %rdi = argc */ + movq %rsp,%rsi /* %rsi = argv */ + pushq %rdi + + leaq 8(%rsi,%rdi,8),%rdx /* %rdx = envp = (8*rdi)+%rsi+8 */ + + movq %rdx, environ(%rip) + call main + movq %rax, %rdi /* return value */ + call exit + hlt +.Lstart: + .size _start,.Lstart-_start + diff --git a/system/x86_64/syscalls.h b/system/x86_64/syscalls.h new file mode 100644 index 0000000..b4f1476 --- /dev/null +++ b/system/x86_64/syscalls.h @@ -0,0 +1,20 @@ +#include <asm/unistd.h> + +#define syscall_weak(name,wsym,sym) \ +.text; \ +.type wsym,@function; \ +.weak wsym; \ +wsym: ; \ +.type sym,@function; \ +.global sym; \ +sym: \ + mov $__NR_##name,%al; \ + jmp __unified_syscall + +#define syscall(name,sym) \ +.text; \ +.type sym,@function; \ +.global sym; \ +sym: \ + mov $__NR_##name,%al; \ + jmp __unified_syscall diff --git a/system/x86_64/unified.S b/system/x86_64/unified.S new file mode 100644 index 0000000..c4dff7d --- /dev/null +++ b/system/x86_64/unified.S @@ -0,0 +1,27 @@ +#define SYS_exit 0x3c + +.text +.weak exit +exit: +.global _exit +_exit: + mov $SYS_exit,%al + +.global __unified_syscall +__unified_syscall: + movzbl %al, %eax + mov %rcx, %r10 + syscall + cmpq $-128, %rax + jbe .Lnoerror + negl %eax + pushq %rax + call __errno_location + popq %rcx + movl %ecx,(%rax) + orq $-1, %rax +.Lnoerror: + + ret +.Lhere: + .size __unified_syscall,.Lhere-__unified_syscall diff --git a/system/x86_64/waitpid.S b/system/x86_64/waitpid.S new file mode 100644 index 0000000..2a85491 --- /dev/null +++ b/system/x86_64/waitpid.S @@ -0,0 +1,10 @@ +.text +.type waitpid,@function +.weak waitpid +waitpid: +.type __libc_waitpid,@function +.global __libc_waitpid +__libc_waitpid: + xor %rcx,%rcx + mov $__NR_wait4,%al + jmp __unified_syscall diff --git a/sysvinit.c b/sysvinit.c new file mode 100644 index 0000000..b9ee198 --- /dev/null +++ b/sysvinit.c @@ -0,0 +1,143 @@ +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <sys/poll.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <alloca.h> +#include "ninitfeatures.h" +#include "initreq.h" +#define IREQ sizeof(struct init_request) + +static char read_buf[IREQ + 4]; +struct init_request *req = (void *)read_buf; +static int infd,outfd,flag_fork; + +#include "open_inout.h" +#include "uid.h" + +void sighandler(int sig) { (void)sig; while (waitpid(-1,0,WNOHANG) > 0); } + +static void do_it(char *A) { + int r=0; + if (flag_fork) { while ((r=fork()) == -1) nano_sleep(1,0); } + if (r==0) { + open_inout(INITROOT); + msg("Starting service: ",A+1); + write(infd, A, str_len(A)); + read(outfd, req, IREQ); + + close(infd); close(outfd); + if (flag_fork) _exit(0); + } +} + +void print_env() { + char *x = req->i.data; + msg("request"," for INIT_CMD_SETENV"); + while (*x) { + msg(x); + x += str_len(x); + x++; + } +} + +int main(int argc, char **argv) { + struct pollfd pfd; + unsigned long ul[2] = {0,0}; + int fd, timeout = -1; + char power[] = "spowerS"; + + errmsg_iam("ninit-sysvinit"); + + if (argc>1 && !str_diff(argv[1], "powerS")) { + char ch; + msg("trying to read and remove: ", INIT_POWERSTATUS); + + fd=open(INIT_POWERSTATUS, O_RDONLY); + if (fd>=0) { read(fd,&ch,1); close(fd); } + unlink(INIT_POWERSTATUS); + + if ('a' <= ch && ch <= 'z') ch -= 32; + switch (ch) { + case 'L': case 'O': break; + default: ch = 'F'; + } + + power[6] = ch; + do_it(power); + return 0; + } + + fd = open(INIT_FIFO, O_RDWR | O_NONBLOCK); + if (fd < 0) { + SYS_mknod(INIT_FIFO,S_IFIFO|0600,0); + return -1; + } + fcntl(fd,F_SETFD,FD_CLOEXEC); + + pfd.fd = fd; + pfd.events = POLLIN; + read_ulongs("sysvinit-timeout", ul, 2); + + if (ul[0] > 0)timeout = 1000 * ul[0]; + flag_fork = (ul[1] != 0); + // msg(" timeout: ",fu(ul[0]), ",fork-mode: ",flag_fork ? "YES" : "NO"); + + if (flag_fork) set_sa(SIGCHLD); + + while (1) { + int flag_known = 0; + switch (poll(&pfd,1,timeout)) { + case -1: + if (errno == EINTR) sighandler(SIGCHLD); break; + return -1; /* poll failed */ + case 1: { + int r = read(fd, req, IREQ); + if (r == (int)IREQ) { + +#ifdef SYSVINIT_DUMP_INITREQ + if ((r=open("/tmp/__##initreq", O_WRONLY | O_APPEND)) >= 0) + { write(r,req,IREQ); close(r); } +#endif + + if (req->magic == INIT_MAGIC) { + char level[] = "slevelS"; + char *A=""; + + switch (req->cmd) { + case INIT_CMD_SETENV: + print_env(); + flag_known=1; + break; + case INIT_CMD_RUNLVL: + r = req->runlevel; + if ('a' <= r && r <= 'z') r -= 32; + level[6] = r; + A = level; + break; + case INIT_CMD_POWEROK: + A = power; + power[6] = 'O'; + break; + case INIT_CMD_POWERFAIL: + A = power; + power[6] = 'F'; + break; + case INIT_CMD_POWERFAILNOW: + A = power; + power[6] = 'L'; + } + + if (*A) { flag_known=1; do_it(A); } + } /* INIT_MAGIC */ + } /* r == sizeof(...) */ + if (flag_known==0) carp("unknown", " request"); + } + break; + default: /* timeout */ + return 0; + } /* poll */ + } +} diff --git a/t_write.h b/t_write.h new file mode 100644 index 0000000..fde8339 --- /dev/null +++ b/t_write.h @@ -0,0 +1,19 @@ +/* timeout write to outfd more than 4096 bytes */ + +static void t_write(void *buf, int len) { +#ifndef INIT_TIMEOUT_WRITE + write(outfd,buf,len); +#else + time_t deadline = time(0) + 1; + while (len > 0) { + int w = write(outfd,buf, (len > PIPE_BUF) ? PIPE_BUF : len); + if (w==-1) { + if (errno == EINTR) continue; + if (errno == EAGAIN && time(0) <= deadline) continue; + return; + } + len -= w; + buf += w; + } +#endif +} diff --git a/tryservice.h b/tryservice.h new file mode 100644 index 0000000..ac615eb --- /dev/null +++ b/tryservice.h @@ -0,0 +1,16 @@ + +static int tryservice(char *home, char *service, char *type, char *other, + void *buffer) { + int r; + open_inout(home); + errmsg_puts(-1,0); + errmsg_puts(-1,type); + errmsg_put(-1,service,str_len(service)+1); + if (other) + errmsg_puts(-1,other); + errmsg_puts(infd,0); + + r=read(outfd,buffer, 4*sizeof(struct process)); + close(infd); close(outfd); + return r; +} diff --git a/tryservice_nsvc.h b/tryservice_nsvc.h new file mode 100644 index 0000000..e83feb0 --- /dev/null +++ b/tryservice_nsvc.h @@ -0,0 +1,34 @@ +#ifdef CLEAN_SERVICE +static char *cleanservice(char* service) { + char* x; + size_t len = str_len(initroot); + if (!byte_diff(service,len,initroot) && service[len] == '/') + service += len+1; + x=service+str_len(service); + while (x>service && x[-1]=='/') --x; + x[0]=0; + return service; +} +#endif + + +/* return nonzero if error */ +static int tryservice(char *service, char ch) { + char *y=buf, *x=service; + int len; + +#ifdef CLEAN_SERVICE + x = cleanservice(x); +#endif + + *y++ = ch; + y += str_copyn(y,x,240); + *y++ = 0; + if (nsvc_other) y += str_copyn(y, nsvc_other, 15); + + write(infd,buf,y-buf); + len=read(outfd,buf,BUFFER_TMP_LEN); + + if (ch != 's') return (len != sizeof(struct process)); + return (len!=1 || buf[0]!='1'); +} @@ -0,0 +1,26 @@ +#ifdef INIT_SYSTEM +#define set_sa(a) system_set_sigaction(a) +#else +#define set_sa(a) set_sigaction(a) +#endif + +#if defined(INIT_SYSTEM) && defined(__i386__) +typedef unsigned short gid__t; +extern int SYS_mknod(const char *path, gid__t mode, gid__t dev); +extern int SYS_chown(const char *path, gid__t owner, gid__t group); +extern int SYS_setgroups(size_t size, const gid__t *list); +#else +typedef gid_t gid__t; +#define SYS_chown chown +#define SYS_mknod mknod +#define SYS_setgroups setgroups +#endif + +#if defined(__linux__) && defined(INIT_SYSTEM) +/* LINUX_REBOOT_MAGIC1 0xfee1dead + LINUX_REBOOT_MAGIC2 672274793 */ +extern int SYS_reboot(int magic, int magic2, int cmd); +#define set_reboot(cmd) SYS_reboot(0xfee1dead, 672274793, cmd) +#else +#define set_reboot reboot +#endif diff --git a/update.c b/update.c new file mode 100644 index 0000000..a7dcc24 --- /dev/null +++ b/update.c @@ -0,0 +1,96 @@ +#include <unistd.h> +#include <fcntl.h> +#include <alloca.h> +#include "ninitfeatures.h" + +static int infd=-1, outfd=-1; +static uint32t env_free=0; +#include "contrib/put_env.h" + +static void die_xx(char *s) { + char *aa[3]; + INIT_ARGS3(aa, "/sbin/ninit","",0); + write(2,"\nupdate: ",9); + write(2,s,str_len(s)); + write(2,"\n",1); + while (1) { + execve(*aa,aa,environ); /* really panic !!! */ + nano_sleep(0,800000000); + } +} +static void safe_read(void *buf, int len) { + if (read(infd,buf,len) != len) die_xx("error reading"); +} +static void safe_write() { + if (write(outfd,"1",1) != 1) die_xx("error writing"); +} + +int main(int Argc, char **Argv) { + uint32t len,i,k; + char **argv, **env, *s; + + s = Argv[0]; + s[str_rchr(s, '/')] = 0; + chdir(s); + + infd=open("../in",O_RDWR); + outfd=open("../out",O_RDWR|O_NONBLOCK); + fcntl(infd,F_SETFD,FD_CLOEXEC); + fcntl(outfd,F_SETFD,FD_CLOEXEC); + + if (infd<0 || outfd<0) { + write(outfd,"0",1); + die_xx("pipes error"); + } + write(outfd,"7",1); + + safe_read(&len,sizeof(len)); + argv = alloca((len+5) * sizeof(char *)); + if (argv==0) die_xx("out of memory"); + safe_write(); + + for (i=0; i<len; i++) { /* argv */ + safe_read(&k, sizeof(k)); + if (k) { + if ((s=alloca(k+1))==0) die_xx("out of memory"); + safe_read(s,k); + s[k] = 0; + } else s = ""; + argv[i] = s; + safe_write(); + } + argv[i] = 0; + + /* ----- environ ----- */ + safe_read(&len,sizeof(len)); + if (len==0) { safe_write(); goto ready; } + + env_free=len+1; + if (environ==0) environ = Argv+Argc; + for (k=0; environ[k]; ) k++; + env = alloca((len+k+5) * sizeof(char *)); + if (env==0) die_xx("out of memory"); + + byte_copy(env, (k+1)*sizeof(char *), environ); + environ=env; + safe_write(); + + for (i=0; i<len; i++) { /* environ */ + safe_read(&k, sizeof(k)); + if (k==0) environ[0] = 0; + else { + if ((s=alloca(k+1))==0) die_xx("out of memory"); + safe_read(s,k); + s[k] = 0; + put_env(s); + } + safe_write(); + } + + ready: + safe_read(&k,sizeof(k)); /* k = "doit" */ + chdir("/"); + execve(*argv, argv, environ); + die_xx("PANIC"); + return 1; +} @@ -0,0 +1,96 @@ +#include <unistd.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <sys/signal.h> +#include <sys/wait.h> +#include "ninitfeatures.h" + +#define SERVICE Argv[1] +#define HOME Argv[2] +#define SYSDIR Argv[3] + +static unsigned long env_free, env_len; +static int infd, outfd; + +#include "process_defs.h" +#include "open_inout.h" +#include "tryservice.h" +#include "contrib/put_env.h" +#include "wait_services.h" + +#define NI_TEXT_FILES 4 +enum { NI_environ,NI_softlimit,NI_wait,NI_cron }; + +int main(int Argc, char **Argv) { + char **env, **xx, *s; + char *tmp[NI_TEXT_FILES]; + static char **aa[NI_TEXT_FILES]; + int i,fd,len; + + errmsg_iam("run-wait"); + if (Argc<4) { + usage: + carp("usage: ",errmsg_argv0," service home sys"); + _exit(1); + } + + if (chdir(HOME) || chdir(SERVICE)) goto usage; + INIT_ARGS4(tmp, "environ","softlimit","wait","cron"); + + for (i=0; i < NI_TEXT_FILES; i++) { + int offset=0; + if ((fd = open(tmp[i], O_RDONLY)) >=0) { + if (i==0) { + if (environ==0) environ = Argv+Argc; + for (env=environ; *env; ++env) env_len++; + offset = env_len + 3; + } + + if (GLOBAL_READ(fd,s, len,24000)) _exit(1); + close(fd); + s[len]=0; + + len = splitmem(0,s,'\n'); if (i==0) env_free=len; + xx=alloca((len+offset+1) * sizeof(char*)); if (xx==0) _exit(1); + xx += offset; + aa[i] = xx; + splitmem(xx,s,'\n'); + skip_comments(xx); + } + } + + if (aa[NI_environ]) { + env = aa[NI_environ] - (env_len + 3); + byte_copy(env, (env_len+1)*sizeof(char *), environ); + environ = env; + + env = aa[NI_environ]; + if (**env==0) environ[0]=0; + for (; *env; env++) put_env(*env); + } + + if (aa[NI_softlimit]) { + errmsg_iam("run-wait: softlimit"); + softlimit(aa[NI_softlimit]); + } + + if (aa[NI_wait]) wait_services(aa[NI_wait], HOME); + + if ((xx=aa[NI_cron])) { + unsigned long cr[2]; + struct process pr[6]; + cron(xx, cr); + if (cr[0]) { + len = tryservice(HOME,SERVICE,"c",fu(cr[0]), pr); + if (cr[1] == 0 && len == sizeof(pr[0]) && pr->pr_finish == 0) return 0; + } + } + + Argv[0] = "-run"; + if (!access("pause-wait", R_OK)) kill(getpid(), SIGSTOP); + if (chdir(HOME) || chdir(SYSDIR)) return 1; + + execve("./run",Argv,environ); + return 1; +} diff --git a/wait_services.h b/wait_services.h new file mode 100644 index 0000000..b99ab79 --- /dev/null +++ b/wait_services.h @@ -0,0 +1,37 @@ +static void wait_services(char **argv, char *home) { + char *s; + struct process pr[6]; + int r,count; + unsigned long ul[2], ug[2] = { RUN_MAXWAIT, 1 }; + + read_ulongs("maxwait", ug, 2); + if (ug[1]==0) ug[1] = 1; + + for (; *argv; argv++) { + s = *argv; + if (*s == 0) continue; + + r = str_chr(s,':'); + if (s[r]) { + s[r] = 0; + r = scan_ulongs(s+r+1,ul,2, scan_ulong,':',&count); + } else r=0; + + if (r<1) ul[0] = ug[0]; + if (r<2) ul[1] = ug[1]; + count = ul[0]; + + /* we have to ask EACH TIME for PID. pidfile changes it */ + while (1) { + r = tryservice(home,s,"p", 0, pr); + if (r == sizeof(pr[0])) + if (pr->pid != 1) { + nano_sleep(ul[1], 0); + if (ul[0]==0) continue; + count -= ul[1]; + if (count > 0) continue; + } + break; + } + } +} |
