├── .travis.yml ├── COPYRIGHT.md ├── README.md ├── Vagrantfile ├── appveyor.yml ├── conf ├── spec.01.i ├── spec.02.i ├── spec.03.i ├── spec.04.i ├── spec.05.i ├── spec.06.i ├── spec.07.i ├── spec.08.i ├── spec.09.i ├── spec.10.i ├── spec.11.i └── spec.12.i ├── doc ├── KMNSIM-specyfikacja.dvi ├── KMNSIM-specyfikacja.log ├── KMNSIM-specyfikacja.pdf ├── KMNSIM-specyfikacja.tex ├── Makefile ├── img │ ├── kmnsim-doc-0.jpeg │ ├── kmnsim-doc-1.jpeg │ ├── kmnsim-doc-2.jpeg │ ├── kmnsim-doc-3.jpeg │ ├── kmnsim-doc-4.jpeg │ ├── kmnsim-doc-5.jpeg │ ├── kmnsim-doc-6.jpeg │ └── kmnsim-doc-7.jpeg └── index.html ├── img └── spec.11.jpg └── src ├── Makefile ├── all.c ├── kmnsim.h ├── queue.h └── subr ├── strdup.c ├── strlcat.c ├── strlcpy.c ├── strsep.c └── subr.h /.travis.yml: -------------------------------------------------------------------------------- 1 | script: cd src && make 2 | language: c 3 | compiler: 4 | - clang 5 | - gcc 6 | os: 7 | - linux 8 | - osx 9 | addons: 10 | apt: 11 | packages: 12 | - graphviz 13 | before_script: 14 | - printenv 15 | - echo "executing before_script" 16 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi 17 | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install graphviz; fi 18 | 19 | script: 20 | - cd src 21 | - make all 22 | -------------------------------------------------------------------------------- /COPYRIGHT.md: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2015, Wojciech Adam Koszek 2 | Copyright (c) 2009 Piotr Matyja 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 1. Redistributions of source code must retain the above copyright 10 | notice, this list of conditions and the following disclaimer. 11 | 2. Redistributions in binary form must reproduce the above copyright 12 | notice, this list of conditions and the following disclaimer in the 13 | documentation and/or other materials provided with the distribution. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 | SUCH DAMAGE. 26 | 27 | 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Koszek-Matyja Network Simulator 2 | ====== 3 | 4 | [![Build Status](https://travis-ci.org/wkoszek/kmnsim.svg)](https://travis-ci.org/wkoszek/kmnsim) 5 | 6 | It's a simple simulator of the Ethernet network architecture. 7 | 8 | You specify network topology in a text file, and run the simulator. 9 | Simulator interprets the text file, and creates virtual hosts, its 10 | interfaces, switches/hubs and their interfaces too. It then creates 11 | connections between those. 12 | 13 | Based on what has been requested in the configuration file, you can then 14 | `ping` the a host from another one and observe the network activity stage by 15 | stage. 16 | 17 | Flow of data is documented in the "report file". Except from report file, 18 | one can also visualize the topology of the network in 19 | [Graphviz](http://www.graphviz.org/), 20 | through the 21 | [The DOT language](http://www.graphviz.org/doc/info/lang.html). 22 | 23 | ## Usage 24 | 25 | Usage of `kmnsim` looks like this: 26 | 27 | Usage: kmnsim [-a] [-d] [-D ] [-T ] [-v] 28 | spec_file 29 | -a direct summary (.out), .dot and .txt files to spec_file.EXT; 30 | -d turn on debug mode; 31 | -D put Graphviz file to 32 | -h print this help 33 | -S put summary file to 34 | -T put text (debug) file to 35 | -v turn verbose mode 36 | 37 | If you want to get all output files to the same prefix path, use option 38 | `-a`. For a debugging, you may want to turn a debugging mode with `-d`, 39 | which will cause more debugging warnings to be printed out. If you want to 40 | just get a .dot file (for graphing with Graphviz), use `-D` flag. `-h` will 41 | print help. Both `-S` and `-T` are used for tracking how the flow of packets 42 | happened in the network. The `-v` turns the verbose mode. One can specify 43 | `-v` multiple tiles (e.g.: `-vv`) to get more verbose output. 44 | 45 | ## Examples 46 | 47 | To generate a summary file, use: 48 | 49 | ./kmnsim -d -v -S spec.4.i out4 50 | 51 | Assuming you want to plot a configuration file from `spec.5.i` file. 52 | 53 | For getting a `.dot` file, you: 54 | 55 | ./kmnsim -d -v -D spec.4.u out4.dot 56 | 57 | (later just use `dot -Tjpg -o out4.dot out4.jpg` to get an JPG file). 58 | Example JPG file (which came from an input file `spec.11.i` in `conf/` 59 | directory) may look like this: 60 | 61 | ![spec.11.i file plotted](img/spec.11.jpg) 62 | 63 | ## Configuration file syntax 64 | 65 | Example configuration file looks like this (see spec/spec.4.i file): 66 | 67 | 68 | 1 host h1 create 69 | 2 host h2 create 70 | 3 71 | 4 iface h1 0 ip 192.168.1.1 72 | 5 iface h1 0 netmask 255.255.255.0 73 | 6 iface h1 0 mac a2:b1:c1:1:2:3 74 | 7 75 | 8 iface h2 0 ip 192.168.1.2 76 | 9 iface h2 0 netmask 255.255.255.0 77 | 10 iface h2 0 mac a3:c3:d3:a2:10:20 78 | 11 79 | 12 hub buh1 create 80 | 13 81 | 14 connect buh1 0 h1 0 82 | 15 connect buh1 1 h2 0 83 | 84 | Following are the descriptions of individual lines: 85 | 86 | a. Lines (1) and (2) create hosts `h1` and `h2` respectively 87 | b. Lines (4--6) configure the interface `0` of host `h1` with IP address, the netmask and the physical MAC address 88 | c. Lines (8--10) are like (b), but for host `h2` 89 | d. Line (12) creates hub called `buh1` 90 | e. Line (14) uses `connect` directive to connect hub's `buh1` interface `0` with host's `h1` interface 0. 91 | f. Line (15) is like line (14), but for host `h2` 92 | 93 | # Author 94 | 95 | - Wojciech Adam Koszek, [wojciech@koszek.com](mailto:wojciech@koszek.com) 96 | - [http://www.koszek.com](http://www.koszek.com) 97 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # All Vagrant configuration is done below. The "2" in Vagrant.configure 5 | # configures the configuration version (we support older styles for 6 | # backwards compatibility). Please don't change it unless you know what 7 | # you're doing. 8 | Vagrant.configure(2) do |config| 9 | # The most common configuration options are documented and commented below. 10 | # For a complete reference, please see the online documentation at 11 | # https://docs.vagrantup.com. 12 | 13 | # Every Vagrant development environment requires a box. You can search for 14 | # boxes at https://atlas.hashicorp.com/search. 15 | config.vm.box = "ubuntu/trusty32" 16 | 17 | # Disable automatic box update checking. If you disable this, then 18 | # boxes will only be checked for updates when the user runs 19 | # `vagrant box outdated`. This is not recommended. 20 | # config.vm.box_check_update = false 21 | 22 | # Create a forwarded port mapping which allows access to a specific port 23 | # within the machine from a port on the host machine. In the example below, 24 | # accessing "localhost:8080" will access port 80 on the guest machine. 25 | # config.vm.network "forwarded_port", guest: 80, host: 8080 26 | 27 | # Create a private network, which allows host-only access to the machine 28 | # using a specific IP. 29 | # config.vm.network "private_network", ip: "192.168.33.10" 30 | 31 | # Create a public network, which generally matched to bridged network. 32 | # Bridged networks make the machine appear as another physical device on 33 | # your network. 34 | # config.vm.network "public_network" 35 | 36 | # Share an additional folder to the guest VM. The first argument is 37 | # the path on the host to the actual folder. The second argument is 38 | # the path on the guest to mount the folder. And the optional third 39 | # argument is a set of non-required options. 40 | # config.vm.synced_folder "../data", "/vagrant_data" 41 | 42 | # Provider-specific configuration so you can fine-tune various 43 | # backing providers for Vagrant. These expose provider-specific options. 44 | # Example for VirtualBox: 45 | # 46 | # config.vm.provider "virtualbox" do |vb| 47 | # # Display the VirtualBox GUI when booting the machine 48 | # vb.gui = true 49 | # 50 | # # Customize the amount of memory on the VM: 51 | # vb.memory = "1024" 52 | # end 53 | # 54 | # View the documentation for the provider you are using for more 55 | # information on available options. 56 | 57 | # Define a Vagrant Push strategy for pushing to Atlas. Other push strategies 58 | # such as FTP and Heroku are also available. See the documentation at 59 | # https://docs.vagrantup.com/v2/push/atlas.html for more information. 60 | # config.push.define "atlas" do |push| 61 | # push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME" 62 | # end 63 | 64 | # Enable provisioning with a shell script. Additional provisioners such as 65 | # Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the 66 | # documentation for more information about their specific syntax and use. 67 | # config.vm.provision "shell", inline: <<-SHELL 68 | # sudo apt-get update 69 | # sudo apt-get install -y apache2 70 | # SHELL 71 | end 72 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | init: 2 | - ps: iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) 3 | #before_build: 4 | #- gettools.bat 5 | build_script: 6 | - choco install make 7 | - SET PATH=C:\Qt\5.5\mingw492_32\bin;%PATH% 8 | - SET PATH=C:\Qt\Tools\mingw492_32\bin;%PATH% 9 | - SET PATH=C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\bin;%PATH% 10 | - ECHO Running NMAKE 11 | - cd src 12 | - make 13 | on_finish: 14 | - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) 15 | -------------------------------------------------------------------------------- /conf/spec.01.i: -------------------------------------------------------------------------------- 1 | # komentarz 2 | host wojtek create 3 | host wojtek remove 4 | host wojtek create 5 | host jola create 6 | 7 | #router chuj create 8 | #router dupa create 9 | 10 | host kuba create 11 | hub hub1 create 12 | hub hub2 create 13 | hub hub1 remove 14 | hub hub2 remove 15 | 16 | 17 | #router r1 create 18 | #router r3 create 19 | #router r1 remove 20 | #router r3 remove 21 | -------------------------------------------------------------------------------- /conf/spec.02.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | host h2 create 3 | 4 | iface h1 0 ip 192.168.1.1 5 | iface h1 0 netmask 255.255.255.0 6 | iface h1 0 mac a2:b1:c1:1:2:3 7 | 8 | #iface h2 1 ip 127.0.0.1 9 | 10 | router r1 create 11 | iface r1 0 ip 127.0.0.1 12 | iface r1 1 ip 127.0.0.2 13 | iface r1 2 ip 127.0.0.3 14 | iface r1 3 ip 127.0.0.4 15 | 16 | -------------------------------------------------------------------------------- /conf/spec.03.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | host h2 create 3 | 4 | iface h1 0 ip 192.168.1.1 5 | iface h1 0 netmask 255.255.255.0 6 | iface h1 0 mac a2:b1:c1:1:2:3 7 | 8 | iface h2 0 ip 192.168.1.2 9 | iface h2 0 netmask 255.255.255.0 10 | iface h2 0 mac a3:c3:d3:a2:10:20 11 | 12 | connect h1 0 h2 0 13 | -------------------------------------------------------------------------------- /conf/spec.04.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | host h2 create 3 | 4 | iface h1 0 ip 192.168.1.1 5 | iface h1 0 netmask 255.255.255.0 6 | iface h1 0 mac a2:b1:c1:1:2:3 7 | 8 | iface h2 0 ip 192.168.1.2 9 | iface h2 0 netmask 255.255.255.0 10 | iface h2 0 mac a3:c3:d3:a2:10:20 11 | 12 | hub buh1 create 13 | 14 | connect buh1 0 h1 0 15 | connect buh1 1 h2 0 16 | -------------------------------------------------------------------------------- /conf/spec.05.i: -------------------------------------------------------------------------------- 1 | hub h1 create 2 | iface h1 0 ip 192.168.1.0 3 | iface h1 0 netmask 255.255.255.0 4 | iface h1 0 mac 00:00:00:11:11:11 5 | -------------------------------------------------------------------------------- /conf/spec.06.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | iface h1 0 ip 192.168.1.1 3 | iface h1 0 netmask 255.255.255.0 4 | iface h1 0 mac 1:2:3:4:5:6 5 | 6 | host h2 create 7 | iface h2 0 ip 192.168.1.2 8 | iface h2 0 netmask 255.255.255.0 9 | iface h2 0 mac a:b:c:d:e:f 10 | 11 | host h1 ping 192.168.1.2 12 | #host h1 ping 192.168.1.2 13 | 14 | #host h2 ping 192.168.1.1 15 | 16 | #host h1 ping 192.168.1.2 17 | #hub uh1 create 18 | #connect uh1 0 h1 0 19 | #connect uh1 1 h2 0 20 | 21 | connect h1 0 h2 0 22 | -------------------------------------------------------------------------------- /conf/spec.07.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | iface h1 0 ip 192.168.1.1 3 | iface h1 0 netmask 255.255.255.0 4 | iface h1 0 mac 1:2:3:4:5:6 5 | 6 | host h2 create 7 | iface h2 0 ip 192.168.1.2 8 | iface h2 0 netmask 255.255.255.0 9 | iface h2 0 mac a:b:c:d:e:f 10 | 11 | connect h1 0 h2 0 12 | -------------------------------------------------------------------------------- /conf/spec.08.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | iface h1 0 ip 192.168.1.1 3 | iface h1 0 netmask 255.255.255.0 4 | iface h1 0 mac 1:2:3:4:5:6 5 | 6 | host h2 create 7 | iface h2 0 ip 192.168.1.2 8 | iface h2 0 netmask 255.255.255.0 9 | iface h2 0 mac a:b:c:d:e:f 10 | 11 | hub hu1 create 12 | 13 | connect h1 0 hu1 3 14 | connect h2 0 hu1 1 15 | 16 | host h1 ping 192.168.1.2 17 | -------------------------------------------------------------------------------- /conf/spec.09.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | iface h1 0 ip 192.168.1.1 3 | iface h1 0 netmask 255.255.255.0 4 | iface h1 0 mac 1:2:3:4:5:6 5 | 6 | host h2 create 7 | iface h2 0 ip 192.168.1.2 8 | iface h2 0 netmask 255.255.255.0 9 | iface h2 0 mac a:b:c:d:e:f 10 | 11 | host h3 create 12 | iface h3 0 ip 192.168.1.5 13 | iface h3 0 netmask 255.255.255.0 14 | iface h3 0 mac d:d:d:e:e:e 15 | 16 | host h4 create 17 | iface h4 0 ip 192.168.1.6 18 | iface h4 0 netmask 255.255.255.0 19 | iface h4 0 mac e:f:d:a:b:c 20 | 21 | hub hu1 create 22 | 23 | connect h1 0 hu1 3 24 | connect h2 0 hu1 1 25 | connect h3 0 hu1 4 26 | connect h4 0 hu1 6 27 | 28 | host h1 ping 192.168.1.2 29 | -------------------------------------------------------------------------------- /conf/spec.10.i: -------------------------------------------------------------------------------- 1 | set simtime 10 2 | 3 | host h1 create 4 | iface h1 0 ip 192.168.1.1 5 | iface h1 0 netmask 255.255.255.0 6 | iface h1 0 mac 1:2:3:4:5:6 7 | 8 | host h2 create 9 | iface h2 0 ip 192.168.1.2 10 | iface h2 0 netmask 255.255.255.0 11 | iface h2 0 mac a:b:c:d:e:f 12 | 13 | host h3 create 14 | iface h3 0 ip 192.168.1.5 15 | iface h3 0 netmask 255.255.255.0 16 | iface h3 0 mac d:d:d:e:e:e 17 | 18 | host h4 create 19 | iface h4 0 ip 192.168.1.6 20 | iface h4 0 netmask 255.255.255.0 21 | iface h4 0 mac e:f:d:a:b:c 22 | 23 | hub hu1 create 24 | 25 | connect h1 0 hu1 3 26 | connect h2 0 hu1 1 27 | connect h3 0 hu1 4 28 | connect h4 0 hu1 6 29 | 30 | host h1 ping 192.168.1.2 31 | -------------------------------------------------------------------------------- /conf/spec.11.i: -------------------------------------------------------------------------------- 1 | set simtime 10 2 | 3 | host h1 create 4 | iface h1 0 ip 192.168.1.1 5 | iface h1 0 netmask 255.255.255.0 6 | iface h1 0 mac 1:2:3:4:5:6 7 | 8 | host h2 create 9 | iface h2 0 ip 192.168.1.2 10 | iface h2 0 netmask 255.255.255.0 11 | iface h2 0 mac a:b:c:d:e:f 12 | 13 | host h3 create 14 | iface h3 0 ip 192.168.1.5 15 | iface h3 0 netmask 255.255.255.0 16 | iface h3 0 mac d:d:d:e:e:e 17 | 18 | host h4 create 19 | iface h4 0 ip 192.168.1.6 20 | iface h4 0 netmask 255.255.255.0 21 | iface h4 0 mac e:f:d:a:b:c 22 | 23 | #switch sw1 create 24 | hub sw1 create 25 | 26 | connect h1 0 sw1 3 27 | connect h2 0 sw1 1 28 | connect h3 0 sw1 4 29 | connect h4 0 sw1 6 30 | 31 | host h1 ping 192.168.1.2 32 | -------------------------------------------------------------------------------- /conf/spec.12.i: -------------------------------------------------------------------------------- 1 | host h1 create 2 | iface h1 0 ip 192.168.1.1 3 | iface h1 0 netmask 255.255.255.0 4 | iface h1 0 mac 1:2:3:4:5:6 5 | 6 | host h2 create 7 | iface h2 0 ip 192.168.1.2 8 | iface h2 0 netmask 255.255.255.0 9 | iface h2 0 mac a:b:c:d:e:f 10 | 11 | host h1 ping 192.168.1.2 12 | host h1 ping 192.168.1.2 13 | 14 | host h2 ping 192.168.1.1 15 | 16 | #host h1 ping 192.168.1.2 17 | #hub uh1 create 18 | #connect uh1 0 h1 0 19 | #connect uh1 1 h2 0 20 | 21 | connect h1 0 h2 0 22 | -------------------------------------------------------------------------------- /doc/KMNSIM-specyfikacja.dvi: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/KMNSIM-specyfikacja.dvi -------------------------------------------------------------------------------- /doc/KMNSIM-specyfikacja.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/KMNSIM-specyfikacja.log -------------------------------------------------------------------------------- /doc/KMNSIM-specyfikacja.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/KMNSIM-specyfikacja.pdf -------------------------------------------------------------------------------- /doc/KMNSIM-specyfikacja.tex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/KMNSIM-specyfikacja.tex -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | KMNSIM-specyfikacja.pdf: KMNSIM-specyfikacja.tex 2 | mex KMNSIM-specyfikacja.tex 3 | dvipdfm KMNSIM-specyfikacja.dvi 4 | -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-0.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-0.jpeg -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-1.jpeg -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-2.jpeg -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-3.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-3.jpeg -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-4.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-4.jpeg -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-5.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-5.jpeg -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-6.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-6.jpeg -------------------------------------------------------------------------------- /doc/img/kmnsim-doc-7.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/img/kmnsim-doc-7.jpeg -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/doc/index.html -------------------------------------------------------------------------------- /img/spec.11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/img/spec.11.jpg -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | CFLAGS=-c -std=c99 -O0 -g -ggdb -Wall -pedantic -Wall 2 | # Remove after I translate the code from Polish 3 | CFLAGS+=-Wno-invalid-source-encoding 4 | 5 | TEST_ALL:=$(wildcard ../conf/*.i) 6 | TEST_EXCLUDE=../conf/spec.02.i ../conf/spec.05.i 7 | TEST_INS:=$(filter-out $(TEST_EXCLUDE),$(TEST_ALL)) 8 | TEST_OUTS:=$(TEST_INS:.i=.o) 9 | TEST_DOTS:=$(TEST_INS:.i=.dot) 10 | TEST_JPGS:=$(TEST_INS:.i=.jpg) 11 | 12 | kmnsim: \ 13 | all.o \ 14 | strdup.o \ 15 | strsep.o \ 16 | strlcat.o \ 17 | strlcpy.o 18 | $(CC) -g -ggdb -o kmnsim \ 19 | all.o \ 20 | strdup.o \ 21 | strsep.o \ 22 | strlcat.o \ 23 | strlcpy.o 24 | 25 | # 26 | # Helper routines. Shouldn't touch UNIX, but must get enabled 27 | # on Windows. Thus, every file has _WIN32 #ifdef'ed. 28 | # 29 | all.o: all.c queue.h kmnsim.h Makefile 30 | $(CC) $(CFLAGS) -o all.o all.c 31 | strdup.o: subr/strdup.c 32 | $(CC) $(CFLAGS) -o strdup.o subr/strdup.c 33 | strsep.o: subr/strsep.c 34 | $(CC) $(CFLAGS) -o strsep.o subr/strsep.c 35 | strlcpy.o: subr/strlcpy.c 36 | $(CC) $(CFLAGS) -o strlcpy.o subr/strlcpy.c 37 | strlcat.o: subr/strlcat.c 38 | $(CC) $(CFLAGS) -o strlcat.o subr/strlcat.c 39 | 40 | analyze: 41 | scan-build -o /tmp/_.kmnsim make -j4 42 | 43 | testdebug: 44 | @echo all $(TEST_ALL) 45 | @echo excluded $(TEST_EXCLUDE) 46 | @echo ins $(TEST_INS) 47 | @echo outs $(TEST_OUTS) 48 | 49 | test: kmnsim $(TEST_OUTS) 50 | dot: kmnsim $(TEST_DOTS) 51 | jpg: kmnsim $(TEST_JPGS) 52 | 53 | all: test dot jpg 54 | 55 | 56 | %.o: %.i 57 | ./kmnsim -d -v -S $@ $< 58 | 59 | %.dot: %.i 60 | ./kmnsim -d -v -D $@ $< 61 | 62 | %.jpg: %.dot 63 | dot -Tjpg -o $@ $< 64 | 65 | clean: 66 | rm -rf kmnsim *.o ../conf/*.out ../conf/*.dot \ 67 | ../conf/*.txt ../conf/*.o ../conf/*.jpg 68 | -------------------------------------------------------------------------------- /src/all.c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wkoszek/kmnsim/459e469713530c5d608db3fa44bde29b3c1c59e5/src/all.c -------------------------------------------------------------------------------- /src/kmnsim.h: -------------------------------------------------------------------------------- 1 | #ifndef _KMNSIM_H_ 2 | #define _KMNSIM_H_ 3 | 4 | /* NOT YET CLASSIFIED */ 5 | extern int cmd_verbose; 6 | extern int flag_debug; 7 | extern int kmnsim_version; 8 | extern int verbose; 9 | 10 | #define VERSION 1 11 | 12 | struct network; 13 | struct hub; 14 | struct host; 15 | struct router; 16 | struct iface; 17 | struct conn; 18 | struct connlist; 19 | struct arptable; 20 | struct pktq; 21 | 22 | /* 23 | * NetworkID 24 | */ 25 | struct nid { 26 | unsigned long _nid_magic; 27 | #define NID_MAGIC 0x6ba531f0 28 | #define NID_INIT(h) do { (h)->_nid_magic = NID_MAGIC; } while (0) 29 | #define NID_ASSERT(h) \ 30 | do { \ 31 | assert((h) != NULL); \ 32 | assert((h)->_nid_magic == NID_MAGIC); \ 33 | } while (0) 34 | 35 | #define NID_LEN 64 36 | char name[NID_LEN]; 37 | int id; 38 | #define NID_HOST 1 39 | #define NID_IFACE 2 40 | #define NID_HUB 3 41 | #define NID_ROUTER 4 42 | int type; 43 | 44 | void *obj; 45 | 46 | TAILQ_ENTRY(nid) next; 47 | }; 48 | TAILQ_HEAD(nids, nid); 49 | 50 | /*------------------------------------------------------------------------*/ 51 | 52 | typedef enum { 53 | IFACE_HOST, 54 | IFACE_HUB, 55 | IFACE_ROUTER 56 | } iface_type_t; 57 | 58 | typedef int ipv4_t[4]; 59 | 60 | #define ETH_LEN 20 61 | #define IP_LEN 20 62 | #define ICMP_LEN 20 63 | #define ICMP_PING_REQUEST 0 64 | #define ICMP_PING_ANSWER 1 65 | 66 | #define ETHER_MAC_LEN 6 67 | #define ADDRV4_LEN 4 68 | 69 | /*------------------------------------------------------------------------*/ 70 | 71 | struct pkt { 72 | unsigned long _pkt_magic; 73 | #define PKT_MAGIC 0xaabbccdd 74 | #define PKT_INIT(h) do { (h)->_pkt_magic = PKT_MAGIC; } while (0) 75 | #define PKT_ASSERT(h) \ 76 | do { \ 77 | assert((h) != NULL); \ 78 | assert((h)->_pkt_magic == PKT_MAGIC); \ 79 | } while (0) 80 | 81 | void *data; 82 | int len; 83 | int id; 84 | 85 | struct iface *src_ifp; 86 | struct iface *dst_ifp; 87 | 88 | TAILQ_ENTRY(pkt) next; 89 | }; 90 | TAILQ_HEAD(pktq, pkt); 91 | 92 | 93 | /*------------------------------------------------------------------------*/ 94 | 95 | struct arp { 96 | unsigned int mac[6]; 97 | unsigned int ip[4]; 98 | TAILQ_ENTRY(arp) next; 99 | }; 100 | TAILQ_HEAD(arptable, arp); 101 | 102 | /*------------------------------------------------------------------------*/ 103 | 104 | struct eth_hdr { 105 | int src_mac[ETHER_MAC_LEN]; 106 | int dst_mac[ETHER_MAC_LEN]; 107 | }; 108 | 109 | struct ip_hdr { 110 | unsigned int src_ipv4[ADDRV4_LEN]; 111 | unsigned int dst_ipv4[ADDRV4_LEN]; 112 | }; 113 | 114 | struct icmp_hdr { 115 | int type; 116 | }; 117 | 118 | struct pkt_icmp { 119 | struct eth_hdr e; 120 | struct ip_hdr ip; 121 | struct icmp_hdr ic; 122 | }; 123 | 124 | /*------------------------------------------------------------------------*/ 125 | 126 | /* 127 | * Interface. 128 | */ 129 | struct iface { 130 | unsigned long _iface_magic; 131 | #define IFACE_MAGIC 0x76b297df 132 | #define IFACE_INIT(h) do { (h)->_iface_magic = IFACE_MAGIC; } while (0) 133 | #define IFACE_ASSERT(h) \ 134 | do { \ 135 | assert((h) != NULL); \ 136 | assert((h)->_iface_magic == IFACE_MAGIC); \ 137 | } while (0) 138 | 139 | struct nid *nid; 140 | struct nid *nid_owner; 141 | 142 | struct pktq inq; 143 | struct pktq outq; 144 | 145 | int flags; 146 | #define IFACE_FLAG_HASIP (1 << 0) 147 | #define IFACE_FLAG_HASNM (1 << 1) 148 | #define IFACE_FLAG_HASMAC (1 << 2) 149 | #define IFACE_FLAG_HASCONN (1 << 3) 150 | 151 | struct iface *conn_ifp; 152 | 153 | unsigned int ipv4[ADDRV4_LEN]; 154 | unsigned int nmv4[ADDRV4_LEN]; 155 | unsigned int mac[ETHER_MAC_LEN]; 156 | 157 | TAILQ_ENTRY(iface) next; 158 | }; 159 | 160 | /*------------------------------------------------------------------------- 161 | * This is how we represent the host. 162 | */ 163 | struct host { 164 | unsigned long _host_magic; 165 | #define HOST_MAGIC 0x9b23ce4f 166 | #define HOST_INIT(h) do { (h)->_host_magic = HOST_MAGIC; } while (0) 167 | #define HOST_ASSERT(h) \ 168 | do { \ 169 | assert((h) != NULL); \ 170 | assert((h)->_host_magic == HOST_MAGIC); \ 171 | } while (0) 172 | 173 | struct iface *iface[1]; 174 | struct nid *nid; 175 | 176 | TAILQ_ENTRY(host) next; 177 | }; 178 | 179 | /*------------------------------------------------------------------------- 180 | * This is our router representation. 181 | */ 182 | struct router { 183 | unsigned long _router_magic; 184 | #define ROUTER_MAGIC 0x5fbe58cd 185 | #define ROUTER_INIT(r) do { (r)->_router_magic = ROUTER_MAGIC; } while (0) 186 | #define ROUTER_ASSERT(r) ASSERT((r)->_router_magic == ROUTER_MAGIC) 187 | 188 | struct nid *nid; 189 | #define ROUTER_IFACES 4 190 | struct iface *iface[ROUTER_IFACES]; 191 | int iface_num; 192 | 193 | TAILQ_ENTRY(router) next; 194 | }; 195 | 196 | /*------------------------------------------------------------------------- 197 | * This is hub structure. 198 | */ 199 | typedef enum { 200 | HUB_MODE_NORMAL, 201 | HUB_MODE_SWITCH 202 | } hub_mode_t; 203 | 204 | struct hub { 205 | unsigned long _hub_magic; 206 | #define HUB_MAGIC 0x3529565f 207 | #define HUB_INIT(h) do { (h)->_hub_magic = HUB_MAGIC; } while (0) 208 | #define HUB_ASSERT(h) ASSERT((h)->_hub_magic == HUB_MAGIC) 209 | 210 | struct nid *nid; 211 | #define HUB_IFACES 8 212 | struct iface *iface[HUB_IFACES]; 213 | int iface_num; 214 | hub_mode_t mode; 215 | 216 | TAILQ_ENTRY(hub) next; 217 | }; 218 | 219 | 220 | /*------------------------------------------------------------------------- 221 | * Connection. 222 | */ 223 | struct conn { 224 | unsigned long _conn_magic; 225 | #define CONN_MAGIC 0x17797ef4 226 | #define CONN_INIT(c) do { (c)->_conn_magic = CONN_MAGIC; } while (0) 227 | #define CONN_ASSERT(c) ASSERT((c)->_conn_magic == CONN_MAGIC) 228 | 229 | struct nid *nid0; 230 | struct nid *nid1; 231 | 232 | TAILQ_ENTRY(conn) next; 233 | }; 234 | TAILQ_HEAD(connlist, conn); 235 | 236 | /*------------------------------------------------------------------------- 237 | * The general mesh in kept in network structure. 238 | */ 239 | struct network { 240 | unsigned long _network_magic; 241 | #define NETWORK_MAGIC 0x1c3a556a 242 | #define NETWORK_INIT(n) do { (n)->_network_magic = NETWORK_MAGIC; } while (0) 243 | #define NETWORK_ASSERT(n) ASSERT((n)->_network_magic == NETWORK_MAGIC) 244 | 245 | struct nids nids; 246 | struct connlist connlist; 247 | struct arptable arptable; 248 | 249 | int version; 250 | int lineno; 251 | int errcode; 252 | int simtime; 253 | 254 | FILE *stream_err; 255 | FILE *stream; 256 | char errmsg[1024]; 257 | }; 258 | 259 | /*------------------------------------------------------------------------- 260 | * Command -- as when parsed from the NULL-terminated buffer. 261 | */ 262 | struct cmd { 263 | unsigned long _cmd_magic; 264 | #define CMD_MAGIC 0x98326190 265 | #define CMD_INIT(c) do { (c)->_cmd_magic = CMD_MAGIC; } while (0) 266 | #define CMD_ASSERT(c) ASSERT((c)->_cmd_magic == CMD_MAGIC) 267 | 268 | #define CMD_LEN 64 269 | char name[CMD_LEN]; 270 | TAILQ_ENTRY(cmd) next; 271 | }; 272 | TAILQ_HEAD(cmdlist, cmd); 273 | 274 | /*------------------------------------------------------------------------- 275 | * Input buffer lenght. 276 | * Used when KMnsim reads text file with network specification. 277 | */ 278 | #define INPUT_BUF_LEN 1024 279 | 280 | 281 | /* the rest for subr.c */ 282 | 283 | /* 284 | * Returns a pointer to the first, non-white character in a string; 285 | * additionally, removes white-spaces from the end of a string [it must 286 | * by 0-terminated. 287 | */ 288 | char *trim(char *s); 289 | 290 | /* 291 | * Checks whether two passed strings are the same. 292 | */ 293 | int streq(const char *a, const char *b); 294 | 295 | #endif /* _KMNSIM_H_ */ 296 | -------------------------------------------------------------------------------- /src/queue.h: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1991, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 4. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * @(#)queue.h 8.5 (Berkeley) 8/20/94 30 | * $FreeBSD: head/sys/sys/queue.h 179210 2008-05-22 14:40:03Z ed $ 31 | */ 32 | 33 | #ifndef _SYS_QUEUE_H_ 34 | #define _SYS_QUEUE_H_ 35 | 36 | #if 0 37 | #include 38 | #endif 39 | 40 | /* 41 | * This file defines four types of data structures: singly-linked lists, 42 | * singly-linked tail queues, lists and tail queues. 43 | * 44 | * A singly-linked list is headed by a single forward pointer. The elements 45 | * are singly linked for minimum space and pointer manipulation overhead at 46 | * the expense of O(n) removal for arbitrary elements. New elements can be 47 | * added to the list after an existing element or at the head of the list. 48 | * Elements being removed from the head of the list should use the explicit 49 | * macro for this purpose for optimum efficiency. A singly-linked list may 50 | * only be traversed in the forward direction. Singly-linked lists are ideal 51 | * for applications with large datasets and few or no removals or for 52 | * implementing a LIFO queue. 53 | * 54 | * A singly-linked tail queue is headed by a pair of pointers, one to the 55 | * head of the list and the other to the tail of the list. The elements are 56 | * singly linked for minimum space and pointer manipulation overhead at the 57 | * expense of O(n) removal for arbitrary elements. New elements can be added 58 | * to the list after an existing element, at the head of the list, or at the 59 | * end of the list. Elements being removed from the head of the tail queue 60 | * should use the explicit macro for this purpose for optimum efficiency. 61 | * A singly-linked tail queue may only be traversed in the forward direction. 62 | * Singly-linked tail queues are ideal for applications with large datasets 63 | * and few or no removals or for implementing a FIFO queue. 64 | * 65 | * A list is headed by a single forward pointer (or an array of forward 66 | * pointers for a hash table header). The elements are doubly linked 67 | * so that an arbitrary element can be removed without a need to 68 | * traverse the list. New elements can be added to the list before 69 | * or after an existing element or at the head of the list. A list 70 | * may only be traversed in the forward direction. 71 | * 72 | * A tail queue is headed by a pair of pointers, one to the head of the 73 | * list and the other to the tail of the list. The elements are doubly 74 | * linked so that an arbitrary element can be removed without a need to 75 | * traverse the list. New elements can be added to the list before or 76 | * after an existing element, at the head of the list, or at the end of 77 | * the list. A tail queue may be traversed in either direction. 78 | * 79 | * For details on the use of these macros, see the queue(3) manual page. 80 | * 81 | * 82 | * SLIST LIST STAILQ TAILQ 83 | * _HEAD + + + + 84 | * _HEAD_INITIALIZER + + + + 85 | * _ENTRY + + + + 86 | * _INIT + + + + 87 | * _EMPTY + + + + 88 | * _FIRST + + + + 89 | * _NEXT + + + + 90 | * _PREV - - - + 91 | * _LAST - - + + 92 | * _FOREACH + + + + 93 | * _FOREACH_SAFE + + + + 94 | * _FOREACH_REVERSE - - - + 95 | * _FOREACH_REVERSE_SAFE - - - + 96 | * _INSERT_HEAD + + + + 97 | * _INSERT_BEFORE - + - + 98 | * _INSERT_AFTER + + + + 99 | * _INSERT_TAIL - - + + 100 | * _CONCAT - - + + 101 | * _REMOVE_HEAD + - + - 102 | * _REMOVE_NEXT + - + - 103 | * _REMOVE + + + + 104 | * 105 | */ 106 | #ifdef QUEUE_MACRO_DEBUG 107 | /* Store the last 2 places the queue element or head was altered */ 108 | struct qm_trace { 109 | char * lastfile; 110 | int lastline; 111 | char * prevfile; 112 | int prevline; 113 | }; 114 | 115 | #define TRACEBUF struct qm_trace trace; 116 | #define TRASHIT(x) do {(x) = (void *)-1;} while (0) 117 | 118 | #define QMD_TRACE_HEAD(head) do { \ 119 | (head)->trace.prevline = (head)->trace.lastline; \ 120 | (head)->trace.prevfile = (head)->trace.lastfile; \ 121 | (head)->trace.lastline = __LINE__; \ 122 | (head)->trace.lastfile = __FILE__; \ 123 | } while (0) 124 | 125 | #define QMD_TRACE_ELEM(elem) do { \ 126 | (elem)->trace.prevline = (elem)->trace.lastline; \ 127 | (elem)->trace.prevfile = (elem)->trace.lastfile; \ 128 | (elem)->trace.lastline = __LINE__; \ 129 | (elem)->trace.lastfile = __FILE__; \ 130 | } while (0) 131 | 132 | #else 133 | #define QMD_TRACE_ELEM(elem) 134 | #define QMD_TRACE_HEAD(head) 135 | #define TRACEBUF 136 | #define TRASHIT(x) 137 | #endif /* QUEUE_MACRO_DEBUG */ 138 | 139 | /* 140 | * Singly-linked List declarations. 141 | */ 142 | #define SLIST_HEAD(name, type) \ 143 | struct name { \ 144 | struct type *slh_first; /* first element */ \ 145 | } 146 | 147 | #define SLIST_HEAD_INITIALIZER(head) \ 148 | { NULL } 149 | 150 | #define SLIST_ENTRY(type) \ 151 | struct { \ 152 | struct type *sle_next; /* next element */ \ 153 | } 154 | 155 | /* 156 | * Singly-linked List functions. 157 | */ 158 | #define SLIST_EMPTY(head) ((head)->slh_first == NULL) 159 | 160 | #define SLIST_FIRST(head) ((head)->slh_first) 161 | 162 | #define SLIST_FOREACH(var, head, field) \ 163 | for ((var) = SLIST_FIRST((head)); \ 164 | (var); \ 165 | (var) = SLIST_NEXT((var), field)) 166 | 167 | #define SLIST_FOREACH_SAFE(var, head, field, tvar) \ 168 | for ((var) = SLIST_FIRST((head)); \ 169 | (var) && ((tvar) = SLIST_NEXT((var), field), 1); \ 170 | (var) = (tvar)) 171 | 172 | #define SLIST_FOREACH_PREVPTR(var, varp, head, field) \ 173 | for ((varp) = &SLIST_FIRST((head)); \ 174 | ((var) = *(varp)) != NULL; \ 175 | (varp) = &SLIST_NEXT((var), field)) 176 | 177 | #define SLIST_INIT(head) do { \ 178 | SLIST_FIRST((head)) = NULL; \ 179 | } while (0) 180 | 181 | #define SLIST_INSERT_AFTER(slistelm, elm, field) do { \ 182 | SLIST_NEXT((elm), field) = SLIST_NEXT((slistelm), field); \ 183 | SLIST_NEXT((slistelm), field) = (elm); \ 184 | } while (0) 185 | 186 | #define SLIST_INSERT_HEAD(head, elm, field) do { \ 187 | SLIST_NEXT((elm), field) = SLIST_FIRST((head)); \ 188 | SLIST_FIRST((head)) = (elm); \ 189 | } while (0) 190 | 191 | #define SLIST_NEXT(elm, field) ((elm)->field.sle_next) 192 | 193 | #define SLIST_REMOVE(head, elm, type, field) do { \ 194 | if (SLIST_FIRST((head)) == (elm)) { \ 195 | SLIST_REMOVE_HEAD((head), field); \ 196 | } \ 197 | else { \ 198 | struct type *curelm = SLIST_FIRST((head)); \ 199 | while (SLIST_NEXT(curelm, field) != (elm)) \ 200 | curelm = SLIST_NEXT(curelm, field); \ 201 | SLIST_REMOVE_NEXT(head, curelm, field); \ 202 | } \ 203 | TRASHIT((elm)->field.sle_next); \ 204 | } while (0) 205 | 206 | #define SLIST_REMOVE_NEXT(head, elm, field) do { \ 207 | SLIST_NEXT(elm, field) = \ 208 | SLIST_NEXT(SLIST_NEXT(elm, field), field); \ 209 | } while (0) 210 | 211 | #define SLIST_REMOVE_HEAD(head, field) do { \ 212 | SLIST_FIRST((head)) = SLIST_NEXT(SLIST_FIRST((head)), field); \ 213 | } while (0) 214 | 215 | /* 216 | * Singly-linked Tail queue declarations. 217 | */ 218 | #define STAILQ_HEAD(name, type) \ 219 | struct name { \ 220 | struct type *stqh_first;/* first element */ \ 221 | struct type **stqh_last;/* addr of last next element */ \ 222 | } 223 | 224 | #define STAILQ_HEAD_INITIALIZER(head) \ 225 | { NULL, &(head).stqh_first } 226 | 227 | #define STAILQ_ENTRY(type) \ 228 | struct { \ 229 | struct type *stqe_next; /* next element */ \ 230 | } 231 | 232 | /* 233 | * Singly-linked Tail queue functions. 234 | */ 235 | #define STAILQ_CONCAT(head1, head2) do { \ 236 | if (!STAILQ_EMPTY((head2))) { \ 237 | *(head1)->stqh_last = (head2)->stqh_first; \ 238 | (head1)->stqh_last = (head2)->stqh_last; \ 239 | STAILQ_INIT((head2)); \ 240 | } \ 241 | } while (0) 242 | 243 | #define STAILQ_EMPTY(head) ((head)->stqh_first == NULL) 244 | 245 | #define STAILQ_FIRST(head) ((head)->stqh_first) 246 | 247 | #define STAILQ_FOREACH(var, head, field) \ 248 | for((var) = STAILQ_FIRST((head)); \ 249 | (var); \ 250 | (var) = STAILQ_NEXT((var), field)) 251 | 252 | 253 | #define STAILQ_FOREACH_SAFE(var, head, field, tvar) \ 254 | for ((var) = STAILQ_FIRST((head)); \ 255 | (var) && ((tvar) = STAILQ_NEXT((var), field), 1); \ 256 | (var) = (tvar)) 257 | 258 | #define STAILQ_INIT(head) do { \ 259 | STAILQ_FIRST((head)) = NULL; \ 260 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 261 | } while (0) 262 | 263 | #define STAILQ_INSERT_AFTER(head, tqelm, elm, field) do { \ 264 | if ((STAILQ_NEXT((elm), field) = STAILQ_NEXT((tqelm), field)) == NULL)\ 265 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 266 | STAILQ_NEXT((tqelm), field) = (elm); \ 267 | } while (0) 268 | 269 | #define STAILQ_INSERT_HEAD(head, elm, field) do { \ 270 | if ((STAILQ_NEXT((elm), field) = STAILQ_FIRST((head))) == NULL) \ 271 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 272 | STAILQ_FIRST((head)) = (elm); \ 273 | } while (0) 274 | 275 | #define STAILQ_INSERT_TAIL(head, elm, field) do { \ 276 | STAILQ_NEXT((elm), field) = NULL; \ 277 | *(head)->stqh_last = (elm); \ 278 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 279 | } while (0) 280 | 281 | #define STAILQ_LAST(head, type, field) \ 282 | (STAILQ_EMPTY((head)) ? \ 283 | NULL : \ 284 | ((struct type *)(void *) \ 285 | ((char *)((head)->stqh_last) - __offsetof(struct type, field)))) 286 | 287 | #define STAILQ_NEXT(elm, field) ((elm)->field.stqe_next) 288 | 289 | #define STAILQ_REMOVE(head, elm, type, field) do { \ 290 | if (STAILQ_FIRST((head)) == (elm)) { \ 291 | STAILQ_REMOVE_HEAD((head), field); \ 292 | } \ 293 | else { \ 294 | struct type *curelm = STAILQ_FIRST((head)); \ 295 | while (STAILQ_NEXT(curelm, field) != (elm)) \ 296 | curelm = STAILQ_NEXT(curelm, field); \ 297 | STAILQ_REMOVE_NEXT(head, curelm, field); \ 298 | } \ 299 | TRASHIT((elm)->field.stqe_next); \ 300 | } while (0) 301 | 302 | #define STAILQ_REMOVE_HEAD(head, field) do { \ 303 | if ((STAILQ_FIRST((head)) = \ 304 | STAILQ_NEXT(STAILQ_FIRST((head)), field)) == NULL) \ 305 | (head)->stqh_last = &STAILQ_FIRST((head)); \ 306 | } while (0) 307 | 308 | #define STAILQ_REMOVE_NEXT(head, elm, field) do { \ 309 | if ((STAILQ_NEXT(elm, field) = \ 310 | STAILQ_NEXT(STAILQ_NEXT(elm, field), field)) == NULL) \ 311 | (head)->stqh_last = &STAILQ_NEXT((elm), field); \ 312 | } while (0) 313 | 314 | /* 315 | * List declarations. 316 | */ 317 | #define LIST_HEAD(name, type) \ 318 | struct name { \ 319 | struct type *lh_first; /* first element */ \ 320 | } 321 | 322 | #define LIST_HEAD_INITIALIZER(head) \ 323 | { NULL } 324 | 325 | #define LIST_ENTRY(type) \ 326 | struct { \ 327 | struct type *le_next; /* next element */ \ 328 | struct type **le_prev; /* address of previous next element */ \ 329 | } 330 | 331 | /* 332 | * List functions. 333 | */ 334 | 335 | #if (defined(_KERNEL) && defined(INVARIANTS)) 336 | #define QMD_LIST_CHECK_HEAD(head, field) do { \ 337 | if (LIST_FIRST((head)) != NULL && \ 338 | LIST_FIRST((head))->field.le_prev != \ 339 | &LIST_FIRST((head))) \ 340 | panic("Bad list head %p first->prev != head", (head)); \ 341 | } while (0) 342 | 343 | #define QMD_LIST_CHECK_NEXT(elm, field) do { \ 344 | if (LIST_NEXT((elm), field) != NULL && \ 345 | LIST_NEXT((elm), field)->field.le_prev != \ 346 | &((elm)->field.le_next)) \ 347 | panic("Bad link elm %p next->prev != elm", (elm)); \ 348 | } while (0) 349 | 350 | #define QMD_LIST_CHECK_PREV(elm, field) do { \ 351 | if (*(elm)->field.le_prev != (elm)) \ 352 | panic("Bad link elm %p prev->next != elm", (elm)); \ 353 | } while (0) 354 | #else 355 | #define QMD_LIST_CHECK_HEAD(head, field) 356 | #define QMD_LIST_CHECK_NEXT(elm, field) 357 | #define QMD_LIST_CHECK_PREV(elm, field) 358 | #endif /* (_KERNEL && INVARIANTS) */ 359 | 360 | #define LIST_EMPTY(head) ((head)->lh_first == NULL) 361 | 362 | #define LIST_FIRST(head) ((head)->lh_first) 363 | 364 | #define LIST_FOREACH(var, head, field) \ 365 | for ((var) = LIST_FIRST((head)); \ 366 | (var); \ 367 | (var) = LIST_NEXT((var), field)) 368 | 369 | #define LIST_FOREACH_SAFE(var, head, field, tvar) \ 370 | for ((var) = LIST_FIRST((head)); \ 371 | (var) && ((tvar) = LIST_NEXT((var), field), 1); \ 372 | (var) = (tvar)) 373 | 374 | #define LIST_INIT(head) do { \ 375 | LIST_FIRST((head)) = NULL; \ 376 | } while (0) 377 | 378 | #define LIST_INSERT_AFTER(listelm, elm, field) do { \ 379 | QMD_LIST_CHECK_NEXT(listelm, field); \ 380 | if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)\ 381 | LIST_NEXT((listelm), field)->field.le_prev = \ 382 | &LIST_NEXT((elm), field); \ 383 | LIST_NEXT((listelm), field) = (elm); \ 384 | (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ 385 | } while (0) 386 | 387 | #define LIST_INSERT_BEFORE(listelm, elm, field) do { \ 388 | QMD_LIST_CHECK_PREV(listelm, field); \ 389 | (elm)->field.le_prev = (listelm)->field.le_prev; \ 390 | LIST_NEXT((elm), field) = (listelm); \ 391 | *(listelm)->field.le_prev = (elm); \ 392 | (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ 393 | } while (0) 394 | 395 | #define LIST_INSERT_HEAD(head, elm, field) do { \ 396 | QMD_LIST_CHECK_HEAD((head), field); \ 397 | if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ 398 | LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);\ 399 | LIST_FIRST((head)) = (elm); \ 400 | (elm)->field.le_prev = &LIST_FIRST((head)); \ 401 | } while (0) 402 | 403 | #define LIST_NEXT(elm, field) ((elm)->field.le_next) 404 | 405 | #define LIST_REMOVE(elm, field) do { \ 406 | QMD_LIST_CHECK_NEXT(elm, field); \ 407 | QMD_LIST_CHECK_PREV(elm, field); \ 408 | if (LIST_NEXT((elm), field) != NULL) \ 409 | LIST_NEXT((elm), field)->field.le_prev = \ 410 | (elm)->field.le_prev; \ 411 | *(elm)->field.le_prev = LIST_NEXT((elm), field); \ 412 | TRASHIT((elm)->field.le_next); \ 413 | TRASHIT((elm)->field.le_prev); \ 414 | } while (0) 415 | 416 | /* 417 | * Tail queue declarations. 418 | */ 419 | #define TAILQ_HEAD(name, type) \ 420 | struct name { \ 421 | struct type *tqh_first; /* first element */ \ 422 | struct type **tqh_last; /* addr of last next element */ \ 423 | TRACEBUF \ 424 | } 425 | 426 | #define TAILQ_HEAD_INITIALIZER(head) \ 427 | { NULL, &(head).tqh_first } 428 | 429 | #define TAILQ_ENTRY(type) \ 430 | struct { \ 431 | struct type *tqe_next; /* next element */ \ 432 | struct type **tqe_prev; /* address of previous next element */ \ 433 | TRACEBUF \ 434 | } 435 | 436 | /* 437 | * Tail queue functions. 438 | */ 439 | #if (defined(_KERNEL) && defined(INVARIANTS)) 440 | #define QMD_TAILQ_CHECK_HEAD(head, field) do { \ 441 | if (!TAILQ_EMPTY(head) && \ 442 | TAILQ_FIRST((head))->field.tqe_prev != \ 443 | &TAILQ_FIRST((head))) \ 444 | panic("Bad tailq head %p first->prev != head", (head)); \ 445 | } while (0) 446 | 447 | #define QMD_TAILQ_CHECK_TAIL(head, field) do { \ 448 | if (*(head)->tqh_last != NULL) \ 449 | panic("Bad tailq NEXT(%p->tqh_last) != NULL", (head)); \ 450 | } while (0) 451 | 452 | #define QMD_TAILQ_CHECK_NEXT(elm, field) do { \ 453 | if (TAILQ_NEXT((elm), field) != NULL && \ 454 | TAILQ_NEXT((elm), field)->field.tqe_prev != \ 455 | &((elm)->field.tqe_next)) \ 456 | panic("Bad link elm %p next->prev != elm", (elm)); \ 457 | } while (0) 458 | 459 | #define QMD_TAILQ_CHECK_PREV(elm, field) do { \ 460 | if (*(elm)->field.tqe_prev != (elm)) \ 461 | panic("Bad link elm %p prev->next != elm", (elm)); \ 462 | } while (0) 463 | #else 464 | #define QMD_TAILQ_CHECK_HEAD(head, field) 465 | #define QMD_TAILQ_CHECK_TAIL(head, headname) 466 | #define QMD_TAILQ_CHECK_NEXT(elm, field) 467 | #define QMD_TAILQ_CHECK_PREV(elm, field) 468 | #endif /* (_KERNEL && INVARIANTS) */ 469 | 470 | #define TAILQ_CONCAT(head1, head2, field) do { \ 471 | if (!TAILQ_EMPTY(head2)) { \ 472 | *(head1)->tqh_last = (head2)->tqh_first; \ 473 | (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ 474 | (head1)->tqh_last = (head2)->tqh_last; \ 475 | TAILQ_INIT((head2)); \ 476 | QMD_TRACE_HEAD(head1); \ 477 | QMD_TRACE_HEAD(head2); \ 478 | } \ 479 | } while (0) 480 | 481 | #define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) 482 | 483 | #define TAILQ_FIRST(head) ((head)->tqh_first) 484 | 485 | #define TAILQ_FOREACH(var, head, field) \ 486 | for ((var) = TAILQ_FIRST((head)); \ 487 | (var); \ 488 | (var) = TAILQ_NEXT((var), field)) 489 | 490 | #define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ 491 | for ((var) = TAILQ_FIRST((head)); \ 492 | (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ 493 | (var) = (tvar)) 494 | 495 | #define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ 496 | for ((var) = TAILQ_LAST((head), headname); \ 497 | (var); \ 498 | (var) = TAILQ_PREV((var), headname, field)) 499 | 500 | #define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ 501 | for ((var) = TAILQ_LAST((head), headname); \ 502 | (var) && ((tvar) = TAILQ_PREV((var), headname, field), 1); \ 503 | (var) = (tvar)) 504 | 505 | #define TAILQ_INIT(head) do { \ 506 | TAILQ_FIRST((head)) = NULL; \ 507 | (head)->tqh_last = &TAILQ_FIRST((head)); \ 508 | QMD_TRACE_HEAD(head); \ 509 | } while (0) 510 | 511 | #define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ 512 | QMD_TAILQ_CHECK_NEXT(listelm, field); \ 513 | if ((TAILQ_NEXT((elm), field) = TAILQ_NEXT((listelm), field)) != NULL)\ 514 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 515 | &TAILQ_NEXT((elm), field); \ 516 | else { \ 517 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 518 | QMD_TRACE_HEAD(head); \ 519 | } \ 520 | TAILQ_NEXT((listelm), field) = (elm); \ 521 | (elm)->field.tqe_prev = &TAILQ_NEXT((listelm), field); \ 522 | QMD_TRACE_ELEM(&(elm)->field); \ 523 | QMD_TRACE_ELEM(&listelm->field); \ 524 | } while (0) 525 | 526 | #define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ 527 | QMD_TAILQ_CHECK_PREV(listelm, field); \ 528 | (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ 529 | TAILQ_NEXT((elm), field) = (listelm); \ 530 | *(listelm)->field.tqe_prev = (elm); \ 531 | (listelm)->field.tqe_prev = &TAILQ_NEXT((elm), field); \ 532 | QMD_TRACE_ELEM(&(elm)->field); \ 533 | QMD_TRACE_ELEM(&listelm->field); \ 534 | } while (0) 535 | 536 | #define TAILQ_INSERT_HEAD(head, elm, field) do { \ 537 | QMD_TAILQ_CHECK_HEAD(head, field); \ 538 | if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ 539 | TAILQ_FIRST((head))->field.tqe_prev = \ 540 | &TAILQ_NEXT((elm), field); \ 541 | else \ 542 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 543 | TAILQ_FIRST((head)) = (elm); \ 544 | (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ 545 | QMD_TRACE_HEAD(head); \ 546 | QMD_TRACE_ELEM(&(elm)->field); \ 547 | } while (0) 548 | 549 | #define TAILQ_INSERT_TAIL(head, elm, field) do { \ 550 | QMD_TAILQ_CHECK_TAIL(head, field); \ 551 | TAILQ_NEXT((elm), field) = NULL; \ 552 | (elm)->field.tqe_prev = (head)->tqh_last; \ 553 | *(head)->tqh_last = (elm); \ 554 | (head)->tqh_last = &TAILQ_NEXT((elm), field); \ 555 | QMD_TRACE_HEAD(head); \ 556 | QMD_TRACE_ELEM(&(elm)->field); \ 557 | } while (0) 558 | 559 | #define TAILQ_LAST(head, headname) \ 560 | (*(((struct headname *)((head)->tqh_last))->tqh_last)) 561 | 562 | #define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) 563 | 564 | #define TAILQ_PREV(elm, headname, field) \ 565 | (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) 566 | 567 | #define TAILQ_REMOVE(head, elm, field) do { \ 568 | QMD_TAILQ_CHECK_NEXT(elm, field); \ 569 | QMD_TAILQ_CHECK_PREV(elm, field); \ 570 | if ((TAILQ_NEXT((elm), field)) != NULL) \ 571 | TAILQ_NEXT((elm), field)->field.tqe_prev = \ 572 | (elm)->field.tqe_prev; \ 573 | else { \ 574 | (head)->tqh_last = (elm)->field.tqe_prev; \ 575 | QMD_TRACE_HEAD(head); \ 576 | } \ 577 | *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ 578 | TRASHIT((elm)->field.tqe_next); \ 579 | TRASHIT((elm)->field.tqe_prev); \ 580 | QMD_TRACE_ELEM(&(elm)->field); \ 581 | } while (0) 582 | 583 | 584 | #ifdef _KERNEL 585 | 586 | /* 587 | * XXX insque() and remque() are an old way of handling certain queues. 588 | * They bogusly assumes that all queue heads look alike. 589 | */ 590 | 591 | struct quehead { 592 | struct quehead *qh_link; 593 | struct quehead *qh_rlink; 594 | }; 595 | 596 | #ifdef __CC_SUPPORTS___INLINE 597 | 598 | static __inline void 599 | insque(void *a, void *b) 600 | { 601 | struct quehead *element = (struct quehead *)a, 602 | *head = (struct quehead *)b; 603 | 604 | element->qh_link = head->qh_link; 605 | element->qh_rlink = head; 606 | head->qh_link = element; 607 | element->qh_link->qh_rlink = element; 608 | } 609 | 610 | static __inline void 611 | remque(void *a) 612 | { 613 | struct quehead *element = (struct quehead *)a; 614 | 615 | element->qh_link->qh_rlink = element->qh_rlink; 616 | element->qh_rlink->qh_link = element->qh_link; 617 | element->qh_rlink = 0; 618 | } 619 | 620 | #else /* !__CC_SUPPORTS___INLINE */ 621 | 622 | void insque(void *a, void *b); 623 | void remque(void *a); 624 | 625 | #endif /* __CC_SUPPORTS___INLINE */ 626 | 627 | #endif /* _KERNEL */ 628 | 629 | #endif /* !_SYS_QUEUE_H_ */ 630 | -------------------------------------------------------------------------------- /src/subr/strdup.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 1988, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 4. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | */ 29 | 30 | #if defined(LIBC_SCCS) && !defined(lint) 31 | static char sccsid[] = "@(#)strdup.c 8.1 (Berkeley) 6/4/93"; 32 | #endif /* LIBC_SCCS and not lint */ 33 | #if 0 34 | #include 35 | __FBSDID("$FreeBSD: src/lib/libc/string/strdup.c,v 1.6 2009/02/03 17:58:20 danger Exp $"); 36 | #endif 37 | 38 | #include 39 | #include 40 | #include 41 | 42 | #if defined(_WIN32) || defined(__linux__) 43 | char * 44 | strdup(const char *str) 45 | { 46 | size_t len; 47 | char *copy; 48 | 49 | len = strlen(str) + 1; 50 | if ((copy = malloc(len)) == NULL) 51 | return (NULL); 52 | memcpy(copy, str, len); 53 | return (copy); 54 | } 55 | #endif /* _WIN32 */ 56 | -------------------------------------------------------------------------------- /src/subr/strlcat.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #if 0 20 | #include 21 | __FBSDID("$FreeBSD: src/lib/libc/string/strlcat.c,v 1.12 2009/02/28 05:15:02 das Exp $"); 22 | #endif 23 | 24 | #include 25 | #include 26 | 27 | #if defined(_WIN32) || defined(__linux__) 28 | /* 29 | * Appends src to string dst of size siz (unlike strncat, siz is the 30 | * full size of dst, not space left). At most siz-1 characters 31 | * will be copied. Always NUL terminates (unless siz <= strlen(dst)). 32 | * Returns strlen(src) + MIN(siz, strlen(initial dst)). 33 | * If retval >= siz, truncation occurred. 34 | */ 35 | size_t 36 | strlcat(char * __restrict dst, const char * __restrict src, size_t siz) 37 | { 38 | char *d = dst; 39 | const char *s = src; 40 | size_t n = siz; 41 | size_t dlen; 42 | 43 | /* Find the end of dst and adjust bytes left but don't go past end */ 44 | while (n-- != 0 && *d != '\0') 45 | d++; 46 | dlen = d - dst; 47 | n = siz - dlen; 48 | 49 | if (n == 0) 50 | return(dlen + strlen(s)); 51 | while (*s != '\0') { 52 | if (n != 1) { 53 | *d++ = *s; 54 | n--; 55 | } 56 | s++; 57 | } 58 | *d = '\0'; 59 | 60 | return(dlen + (s - src)); /* count does not include NUL */ 61 | } 62 | #endif 63 | -------------------------------------------------------------------------------- /src/subr/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #if 0 20 | #include 21 | __FBSDID("$FreeBSD: src/lib/libc/string/strlcpy.c,v 1.11 2009/02/28 05:15:02 das Exp $"); 22 | #endif 23 | 24 | #include 25 | #include 26 | 27 | #if defined(_WIN32) || defined(__linux__) 28 | /* 29 | * Copy src to string dst of size siz. At most siz-1 characters 30 | * will be copied. Always NUL terminates (unless siz == 0). 31 | * Returns strlen(src); if retval >= siz, truncation occurred. 32 | */ 33 | size_t 34 | strlcpy(char * __restrict dst, const char * __restrict src, size_t siz) 35 | { 36 | char *d = dst; 37 | const char *s = src; 38 | size_t n = siz; 39 | 40 | /* Copy as many bytes as will fit */ 41 | if (n != 0) { 42 | while (--n != 0) { 43 | if ((*d++ = *s++) == '\0') 44 | break; 45 | } 46 | } 47 | 48 | /* Not enough room in dst, add NUL and traverse rest of src */ 49 | if (n == 0) { 50 | if (siz != 0) 51 | *d = '\0'; /* NUL-terminate dst */ 52 | while (*s++) 53 | ; 54 | } 55 | 56 | return(s - src - 1); /* count does not include NUL */ 57 | } 58 | #endif 59 | -------------------------------------------------------------------------------- /src/subr/strsep.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1990, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 4. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | */ 29 | 30 | #if defined(LIBC_SCCS) && !defined(lint) 31 | static char sccsid[] = "@(#)strsep.c 8.1 (Berkeley) 6/4/93"; 32 | #endif /* LIBC_SCCS and not lint */ 33 | #if 0 34 | #include 35 | __FBSDID("$FreeBSD: src/lib/libc/string/strsep.c,v 1.7 2009/02/03 17:58:20 danger Exp $"); 36 | #endif 37 | 38 | #include 39 | #include 40 | 41 | #if defined(_WIN32) || defined(__linux__) 42 | /* 43 | * Get next token from string *stringp, where tokens are possibly-empty 44 | * strings separated by characters from delim. 45 | * 46 | * Writes NULs into the string at *stringp to end tokens. 47 | * delim need not remain constant from call to call. 48 | * On return, *stringp points past the last NUL written (if there might 49 | * be further tokens), or is NULL (if there are definitely no more tokens). 50 | * 51 | * If *stringp is NULL, strsep returns NULL. 52 | */ 53 | char * 54 | strsep(char **stringp, const char *delim) 55 | { 56 | char *s; 57 | const char *spanp; 58 | int c, sc; 59 | char *tok; 60 | 61 | if ((s = *stringp) == NULL) 62 | return (NULL); 63 | for (tok = s;;) { 64 | c = *s++; 65 | spanp = delim; 66 | do { 67 | if ((sc = *spanp++) == c) { 68 | if (c == 0) 69 | s = NULL; 70 | else 71 | s[-1] = 0; 72 | *stringp = s; 73 | return (tok); 74 | } 75 | } while (sc != 0); 76 | } 77 | /* NOTREACHED */ 78 | } 79 | #endif /* _WIN32 */ 80 | -------------------------------------------------------------------------------- /src/subr/subr.h: -------------------------------------------------------------------------------- 1 | #ifndef _SUBR_H_ 2 | #define _SUBR_H_ 3 | 4 | #if defined(_WIN32) || defined(__linux__) 5 | char *strdup(const char *str); 6 | size_t strlcat(char * __restrict dst, const char * __restrict src, size_t siz); 7 | size_t strlcpy(char * __restrict dst, const char * __restrict src, size_t siz); 8 | char *strsep(char **stringp, const char *delim); 9 | #endif 10 | 11 | #endif /* _SUBR_H_ */ 12 | --------------------------------------------------------------------------------