Plan 9 is a distributed operating system made by Bell Labs. The OS is free and open source. Plan 9 is similar to Unix in some ways, but Plan 9 is meant to be an improvement unto Unix and POSIX.
FUN FACT: The mascot for Plan 9 is a rabbit named “Glenda”.
Plan 9 has some features familiar to Unix users. For instance, Plan 9 uses ProcFS and applies the “everything is a file” concept. However, applications from Unix, Linux, and other systems do not work on Plan 9. Some Linux software works on the Linux emulator (linuxemu). Although, the emulator is not yet complete.
The default shell is “rc”. Many of the usual Unix commands (like ls, cp, rm, etc.) can be used. However, despite the same names, the code used to make these commands are entirely different. Plan 9 does not use any GNU software, neither will any work with help from linuxemu. rc is similar to Bash. However, there are some differences. While Bash’s syntax is ALGOL-like, rc uses C-like syntax.
A GUI is also available to Plan 9 named “rio”. rio is a windowing system. rio does not rely on display servers (such as X11). In fact, rio functions as a display server and window manager. rio supports the alpha bit (transparency).
Plan 9 uses a hybrid kernel that has attributes of both monolithic kernels and microkernels. The kernel supports a variety of platforms such as x86, x86-64, MIPS, SPARC, etc.. Plan 9 has also been ported to ARM platforms such as the Raspberry Pi motherboard.
Deltabotics would provide HTTPS links to the work of Plan 9 by Bell Labs, but the HTTPS certs were “insecure”. You make your own opinion.
Plan 9 is best known for its 9P network protocol. 9P (also called Styx or “Plan 9 Filesystem Protocol”) also serves as a communications protocol between the internal components of the system. The fourth edition of Plan 9 introduced a modified 9P protocol called 9P2000.
FUN FACT: The Styx protocol used in the Inferno operating system is a variant of 9P.
The C programming language (and similar languages) use a coding concept called “pointers”. Pointers point to a memory address. The pointer itself does not contain the data. Rather, the pointer stores the memory address (like the index of a book). Many people may have problems understanding pointers and addressing, so I hope this helps.
A pointer is a programming object that references a memory location. A pointer contains the memory address of a particular part of memory. A pointer is like a page number in the index of a book. The page number is the data stored by pointer. The words on the actual page is like the data in memory.
NOTE: “Dereferencing” is the act of obtaining the data on memory pointed to by the pointer.
A pointer must be of the same datatype as the data to which it points. Also, a pointer must be initialized before it can be used.
To make a pointer that points to an integer in memory, use the below code.
int int_in_mem = 32; // Initialize and declare integer
int* int_ptr; // Declare
int_ptr = &int_in_mem; // Initialize
int* ptr2 = ptr; // Create a second pointer that points to the same data
In the example, “int_in_mem” is an integer in memory. “int_ptr” only stores the memory address of the location of “int_in_mem“. “int_in_mem” has the value “32” while “int_ptr” contains the value the indicates where in memory “int_in_mem” resides. “ptr2” points at the same memory location as “ptr“. This is helpful when a particular memory location must be remembered when the other pointer will be changed to point to another location.
The ampersand (&) means memory location. Therefore, “&int_in_mem” gives the memory address of the data “int_in_mem“. The code &int_ptr would give the address in memory where “int_ptr” is stored. Thus, it is possible to have a pointer that points to a pointer. Also, the ampersand is helpful if code needs to know the literal memory address of a particular variable.
In the example, “int_ptr” is the plain pointer. *int_ptr is the data at that memory location (in this case, “32”). *int_ptr++ reads the value of the memory location and then increments the pointer. This means that the pointer will point to the memory location that comes after the location that is storing the “32”. (*int_ptr)++ will increment the data stored at that location. Thus, “32” will become “33”, but the pointer itself remains unchanged. Below are various pointer notations and their meaning and effects.
Pointer
Memory Address
Data
ptr
Access memory address
Unchanged
*ptr
Unchanged
Access data on memory
*ptr++
Increment address after reading
Unchanged
*(ptr++)
Increment address after reading
Unchanged
(*ptr)++
Unchanged
Increment data after reading
*++ptr
Increment address before reading
Unchanged
*(++ptr)
Increment address before reading
Unchanged
++*ptr
Unchanged
Increment data before reading
++(*ptr)
Unchanged
Increment data before reading
--*ptr
Unchanged
Decrement data before reading
ptr*++
Invalid
Invalid
ptr++*
Invalid
Invalid
Be careful when declaring multiple pointers. For instance, int* ptr_a, ptr_b; is equivalent to int* ptr_a; int ptr_b;.
Arrays notation is a special form of a pointer as seen in the table below.
Array
Pointer Equivalent
array
ptr*
array[1]
*(ptr + 1)
array[2]
*(ptr + 2)
array[1]
*(array + 1)
An array is a collection of elements of data. Arrays are stored on memory and pointers are used to point and retrieve members/elements from the array. For instance, array[0] is a pointer to the first element on the array (computers start counting at zero). In many languages (such as C), strings are arrays of characters.
If using two pointers, the length of an array can be measured. For instance, the below code creates a string (character array) and measures the length of the string.
distance will contain the value “5” since the memory address pointed to by “second_ptr” minus the address “first_ptr” is five. Thus, there are five elements from the first element of the array/string ([0]) to the sixth element ([5]). Remember, computers start counting at zero.
Now for another example.
int int_in_mem = 32; // Initialize and declare integer
int* int_ptr; // Declare
int_ptr = &int_in_mem; // Initialize
int* ptr2 = ptr; // Create a second pointer that points to the same data
int our_num = *ptr2; // Access data at the memory location indicated by ptr2
int num2 = (*int_ptr)++; // Access data at the memory location indicated by ptr2
In the above example, int_in_mem stores “32” while both int_ptr and ptr2 store the location of int_in_mem. our_num contains “32” because the code retrieves the data stored at the pointed memory location. num2 will contain “33” because the code gets the data on memory and then increments the value before storing it in num2.
To change the value of data in memory use the below code which changes “32” to “7”. If the code were int_ptr = 7; instead of *int_ptr = 7;, then int_ptr would point to memory address 7.
int int_in_mem = 32; // Initialize and declare integer
int* int_ptr; // Declare
int_ptr = &int_in_mem; // Initialize
*int_ptr = 7; // Place "7" at the pointed memory address
As for pointers to pointers, the below code, d points to the memory address that stores the “3” placed in a.
int a = 3;
int *b = &a;
int **c = &b;
int ***d = &c;
A NULL pointer (such as int* ptr = 0;) is a pointer that pointers to zero. This means that it does not point to any data.
A function pointer is a pointer to a function. Function pointers allow code to take functions as arguments which may be used to tell a function to use a particular function.
void test_func(int x) { printf("%d\n", x); } // Function
void (*func_ptr)(int); // Declare function pointer
func_ptr = &test_func; // Initialize function pointer
func_ptr(2); // Same as test_func(2)
There are many different type-qualifiers in the C programming language. Here is a brief description of some type qualifiers in C (and similar languages).
Do remember the “Clockwise/Spiral Rule” – Read the type qualifiers backwards
int* – pointer to int
int const* – pointer to const int (const int* == int const*)
int *const – const pointer to int
int const *const – const pointer to const int (const int* const == int const *const)
int ** – pointer to pointer to int
int **const – const pointer to pointer to int
int *const * – pointer to const pointer to int
int const ** – pointer to pointer to const int
int *const *const – const pointer to const pointer to int
volatile int *const – constant pointer to volatile int
void (*signal(int, void (*fp)(int)))(int) – signal is a function passing an int and a pointer to a function passing an int returning nothing (void) returning a pointer to a function passing an int returning nothing (void)
Storage classes (listed below) come before type-qualifiers (also listed below). Only one storage class can be used when declaring a variable. Both storage and type qualifiers come before the datatype.
Storage Classes
auto – Stored in stack during the code-block
extern – Lasts the whole program, block, or compilation unit; globally visible
register – Stored in stack or CPU-register during the code block
static – Lasts the whole program, block, or compilation unit; private in program
typedef – The data specifies a new datatype
__thread – Thread-local-storage; one instance per thread
_Thread_local – Thread-local data
Type-Qualifiers
const – Value does not change; read-only
restrict – For the lifetime of the pointer, the object can only be accessed via the pointer
volatile – Optimizing-compilers must not change
_Atomic – Map a variable to a basic built-in type (depending on the processor) so that reading and writing are guaranteed to happen in a single instruction
VxWorks is a Real-Time Operating System (RTOS) used for embedded systems since 1987. The operating system supports both Symmetric Multiprocessing (SMP) and Asymmetric Multiprocessing (AMP) plus mixed modes. In addition, the supported platforms include x86, x86-64, ARM, PowerPC, MIPS, ColdFire, XScale, SH-4, and others. The operating system uses the monolithic kernel design. VxWorks is a certified POSIX system. However, VxWorks is not a Unix system. Rather, it is an alternative to Unix and Unix-like systems.
VxWorks supports many standard computer ports and network protocols such as Bluetooth, USB, IPv6, FireWire, etc. Some supported filesystems include High Reliability File System (HRFS), FAT-based file system (DOSFS), Network File System (NFS), and True Flash-Filesystem (TFFS or TrueFFS). DOSFS is comparable to FAT16 and FAT32 on Microsoft’s Windows or VFAT on Linux. Like many modern filesystems, VxWorks uses a Graphical User Interface (GUI).
VxWorks can run on many host systems including Linux (Ubuntu, SUSE, RedHat, and others), Windows, and Solaris.
Many computer users are familiar with the basic idea of filesystems. A storage device is divided into partitions each formatted to a particular filesystem that holds files. Just as the filesystem hold the files, a partition table holds the filesystems. There are a few partition table types.
Master Boot Record (MBR) – Most IBM-based PC storage units use this partition table format (such as thumb-drives and SD cards). MBR is often referred to as the msdos partition table. The MBR can only support storage devices up to two terabytes. MBR supports the concept of logical and primary partitions. A storage unit with the MBR table can only have up to four primary partitions. Many users wanting to make a multiboot system with more than four Linux distros often have the problem of not being able to support more partitions. Remember, logical partitions cannot be made bootable. Multiboot systems must use a different partition table discussed later.
GUID Partition Table (GPT) – Some IBM-based PC storage units have GPT, although it is usually because the user reformatted from MBR to GPT. However, most Intel and ARM-based Mac systems use GPT by default. The GPT partition table offers many improvements over MBR. GPT can support storage units up to over nine zettabytes. GPT is also the most highly recommended partition table for computers needing more than four operating systems on one hard-drive. For example, if a computer with a ten terabyte hard-disk is meant to be a multiboot system for seven different Linux distros, then GPT should be used. Most Unix and Unix-like operating systems can fully support GPT. However, most Windows systems cannot run on a GPT partition table. As for Mac systems, only the Intel and ARM-based ones can boot from GPT.
Apple Partition Map (APM) – The PowerPC-based Mac systems can only boot from APM partition tables. This is usually referred to as the Mac or Apple partition table. Linux and Intel-based Macs can use APM. Windows does not support APM.
Amiga rigid disk block (RDB) – Amiga systems use the RDB partition table. These partition tables support up to about 4*10^19TB. That is forty quintillion terabytes.
AIX – The AIX partition table is used by proprietary AIX systems. By default, Linux does not natively support the AIX partition table.
BSD – BSD Unix systems can use the BSD partition table. Linux and Windows cannot read BSD partition tables.
Others – Some other partition table formats are listed below. The below listed are very rarely used. Not much information can be seen on the Internet about them.
dvh
humax
pc98
sgi
sun
Formatting a Partition Table
There are many ways to change/set a partition table. We will use the GUI interface.
To change or reformat a partition table, use Gparted and click “Device > Create Partition Table”. Then, choose the desired partition table.
WARNING: Changing the partition table will erase the filesystems, partitions, and files. This is a more “low-level” format. However, the files are not truly gone (there are ways to recover such files, but that is beyond the scope of this article).
You may also be wondering which is the best one for you. Well, use MBR with Windows and portable storage devices, APM on PowerPC Macs, RDB on Amiga, and GPT on all other systems.
On Linux systems, numerous users often come across a program or process that locks up. The user will usually kill the software if the system does not do it first. Users may be familiar with some of the kill commands and signals, but does anyone understand all of them? There are four common kill commands and a total of 64 kill signals.
kill – The kill command will kill a process using the kill signal and PID given by the user. To use the SIGKILL signal with “kill”, type one of the following for a process with a PID of 0710.
kill -9 0710 kill -SIGKILL 0710
The kill command accepts either the signal number or name (signals have both a number and name that can be referenced). The name must be in all caps.
killall – The killall command kills all process with a particular name. For instance, Nautilus may be running several times. To kill all of them type “killall -SIGQUIT nautilus”. Also, if Firefox is running once and the user does not know the PID, use the killall command – “killall -9 firefox”. The killall command also uses case-sensitive kill signals (they are all uppercase). Below demonstrates what will happen when the kill signal is typed in lowercase. Notice that the command uses the “s” as a parameter and then it does not know what to do with the rest of the information. It then tries to use “igkill” as a kill signal, but no such signal exists.
pkill – This command is a lot like killall except it allows partial names. So, “pkill -9 unity” will kill any process whose name begins with “unity”.
xkill – This command allows users to kill a command by clicking the window. In a terminal, type “xkill” and then the cursor will change. Next, click a window to kill. The application should disappear and leave the memory. Then, the cursor will return to normal.
There are many kill signals that each serve a particular purpose. Typing “kill -l” will list the kill signals. Notice that all kill signals begin with “SIG”; this means SIGnal.
NOTE: Yes, certain numbers are missing because those signals are not supported on my system, or they were discontinued. If you run the same command, you may have different numbers missing/available.
TIP: Signals 1, 3, 9, and 15 will be available on all systems. Those are the most common signals. It is important to learn those very well when administering Linux systems.
Kill signals are not only used to close locked-up applications, but also stop software from performing unallowed tasks. This means some of these kill signals are part of security. Surprisingly, kill commands not only stop/kill processes but they also pause, continue, and restart processes.
SIGHUP – The SIGHUP signal disconnects a process from the parent process. This an also be used to restart processes. For example, “killall -SIGUP compiz” will restart Compiz. This is useful for daemons with memory leaks.
SIGINT – This signal is the same as pressing ctrl-c. On some systems, “delete” + “break” sends the same signal to the process. The process is interrupted and stopped. However, the process can ignore this signal.
SIGQUIT – This is like SIGINT with the ability to make the process produce a core dump.
SIGILL – When a process performs a faulty, forbidden, or unknown function, the system sends the SIGILL signal to the process. This is the ILLegal SIGnal.
SIGTRAP – This signal is used for debugging purposes. When a process has performed an action or a condition is met that a debugger is waiting for, this signal will be sent to the process.
SIGABRT – This kill signal is the abort signal. Typically, a process will initiate this kill signal on itself.
SIGBUS – When a process is sent the SIGBUS signal, it is because the process caused a bus error. Commonly, these bus errors are due to a process trying to use fake physical addresses or the process has its memory alignment set incorrectly.
SIGFPE – Processes that divide by zero are killed using SIGFPE. Imagine if humans got the death penalty for such math. NOTE: The author of this article was recently drug out to the street and shot for dividing by zero.
SIGKILL – The SIGKILL signal forces the process to stop executing immediately. The program cannot ignore this signal. This process does not get to clean-up either.
SIGUSR1 – This indicates a user-defined condition. This signal can be set by the user by programming the commands in sigusr1.c. This requires the programmer to know C/C++.
SIGSEGV – When an application has a segmentation violation, this signal is sent to the process.
SIGUSR2 – This indicates a user-defined condition.
SIGPIPE – When a process tries to write to a pipe that lacks an end connected to a reader, this signal is sent to the process. A reader is a process that reads data at the end of a pipe.
SIGALRM – SIGALRM is sent when the real time or clock time timer expires.
SIGTERM – This signal requests a process to stop running. This signal can be ignored. The process is given time to gracefully shutdown. When a program gracefully shuts down, that means it is given time to save its progress and release resources. In other words, it is not forced to stop. SIGINT is very similar to SIGTERM.
SIGCHLD – When a parent process loses its child process, the parent process is sent the SIGCHLD signal. This cleans up resources used by the child process. In computers, a child process is a process started by another process know as a parent.
SIGCONT – To make processes continue executing after being paused by the SIGTSTP or SIGSTOP signal, send the SIGCONT signal to the paused process. This is the CONTinue SIGnal. This signal is beneficial to Unix job control (executing background tasks).
SIGSTOP – This signal makes the operating system pause a process’s execution. The process cannot ignore the signal.
SIGTSTP – This signal is like pressing ctrl-z. This makes a request to the terminal containing the process to ask the process to stop temporarily. The process can ignore the request.
SIGTTIN – When a process attempts to read from a tty (computer terminal), the process receives this signal.
SIGTTOU – When a process attempts to write from a tty (computer terminal), the process receives this signal.
SIGURG – When a process has urgent data to be read or the data is very large, the SIGURG signal is sent to the process.
SIGXCPU – When a process uses the CPU past the allotted time, the system sends the process this signal. SIGXCPU acts like a warning; the process has time to save the progress (if possible) and close before the system kills the process with SIGKILL.
SIGXFSZ – Filesystems have a limit to how large a file can be made. When a program tries to violate this limit, the system will send that process the SIGXFSZ signal.
SIGVTALRM – SIGVTALRM is sent when CPU time used by the process elapses.
SIGPROF – SIGPROF is sent when CPU time used by the process and by the system on behalf of the process elapses.
SIGWINCH – When a process is in a terminal that changes its size, the process receives this signal.
SIGIO – Alias to SIGPOLL or at least behaves much like SIGPOLL.
SIGPWR – Power failures will cause the system to send this signal to processes (if the system is still on).
SIGSYS – Processes that give a system call an invalid parameter will receive this signal.
SIGRTMIN* – This is a set of signals that varies between systems. They are labeled SIGRTMIN+1, SIGRTMIN+2, SIGRTMIN+3, ……., and so on (usually up to 15). These are user-defined signals; they must be programmed in the Linux kernel’s source code. That would require the user to know C/C++.
SIGRTMAX* – This is a set of signals that varies between systems. They are labeled SIGRTMAX-1, SIGRTMAX-2, SIGRTMAX-3, ……., and so on (usually up to 14). These are user-defined signals; they must be programmed in the Linux kernel’s source code. That would require the user to know C/C++.
SIGEMT – Processes receive this signal when an emulator trap occurs.
SIGINFO – Terminals may sometimes send status requests to processes. When this happens, processes will also receive this signal.
SIGLOST – Processes trying to access locked files will get this signal.
SIGPOLL – When a process causes an asynchronous I/O event, that process is sent the SIGPOLL signal.
Users can use these kill signals using one of the four kill commands. When sending a signal to a process owned by another user (like root), the user needs admin privileges and must use the sudo command. Be careful though, misuse of these signals can cause system damage. For instance, using SIGTERM on a GUI process like Compiz, X11, XFCE, Unity, Gnome-shell, etc. will make the system unviewable.
A Programmable Logic Controller (PLC) is a digital computer (or microprocessor) that processes logic based on the inputs and then sends the proper outputs. Such devices are typically used in industrial settings for automation. PLCs are used rather than PCs (personal computers) because PLCs are able to withstand harsher environments than PCs. PLCs are real-time systems, and they are more durable and easily programmable than relays (electrically operated electromagnet switches). PLCs may be simple and inexpensive, or they can be expensive and complex devices (depending on the needs).
PLCs can be programmed using ladder logic (which is similar to relay logic), programming languages (like C/C++, assembly, etc.), state logic (state transition diagram), function block diagrams (FBD), or other methods. There are some PLC-specific programming languages such as Instruction List (similar to Assembly) and Structured Text (similar to Pascal). PLCs can be programmed using a PC that is connected via Ethernet or other means such as RS-232. The code is then stored on EEPRO or EPROM chips.
PLCs may use one of two memory organizations – the rack-based system or the tag-based system. In the rack-based system, one portion of memory is for program files and the other is for data files. The data files are then further sub-divided by file-type. As for the tag-based system, all data is given a named memory address called a variable. For instance, the SLC 500 uses the rack-based system while the Logix series uses the tag-based system. As another example, the PLC 5 uses the rack-based addressing format. This means when specifying an input on the second group of the third rack, the address would be I:2/1. The first rack or group is zero and the second is designated as “1”.
IEC 61131 is a set of standards for PLCs. IEC 61131-3 (IEC 61131 part 3) specifically sets standards for the programming languages of PLCs. For instance, this standard specifies that booleans are one bit. Other data types and their values, description, and/or sizes are listed below. The IEC 61131-3 standard specifies that PLCs use the dollar sign ($) as the escape character in strings. All float-points follow the IEEE 754 standards.
BOOL – 1 bit
BYTE – 8 bits (1 byte)
WORD – 16 bits (2 bytes)
DWORD (double word) – 32 bits (4 bytes)
LWORD (long word) – 64 bits (8 bytes)
INTEGER – whole numbers
SINT – signed short integer (1 byte)
INT – signed integer (2 bytes)
DINT – double integer (4 bytes)
LINT – long integer (8 bytes)
USINT – unsigned short integer (1 byte)
UINT – unsigned integer (2 bytes)
UDINT – unsigned double integer (4 bytes)
ULINT – unsigned long integer (8 bytes)
REAL – float-point numbers (4 bytes)
LREAL – long float-points (8 bytes)
TIME – timers, counters, duration, etc.
DATE – calendar date
TIME_OF_DAY – clock time
DATE_AND_TIME – time and date
STRING – character strings enclosed in single-quotes
WSTRING – wide-string (multi-byte strings)
ARRAYS – multiple values in one variable
TYPE – single type
STRUCT – a data-type made of multiple types
ANY – a type that represents the above types
NOTE: Sub-types of ANY includes ANY_DERIVED, ANY_ELEMENTARY, ANY_MAGNITUDE, ANY_NUM, ANY_INT, ANY_BIT, ANY_STRING, and ANY_DATE.
PLCs and PCs have some features in common. For instance, PLCs are capable of having an operating system, such as VxWorks or OS-9. Also, PLCs are susceptible to viruses such as the Stuxnet virus. As for physical similarities, PCs and PLCs contain a motherboard, processor, memory, and expansion slots.