Magic Numbers of the Linux Reboot() System Call

Magic numbers of the Linux reboot() system call

Just a guess, but those numbers look more interesting in hex:

672274793 = 0x28121969
85072278 = 0x05121996
369367448 = 0x16041998
537993216 = 0x20112000

Developers' or developers' children's birthdays?

Regarding finding the syscall implementation, I did a git grep -n LINUX_REBOOT_MAGIC2 and found the definition in kernel/sys.c. The symbol sys_reboot is generated by the SYSCALL_DEFINE4(reboot, ... gubbins, I suspect.

system call reboot and magic numbers

The significance of the allowed set of magic2 numbers is that, when expressed in hexadecimal, they represent dates-of-birth (specifically, of Linus Torvalds and his three children).

This really lowers the bar on silly interview questions!

Linux reboot system call returns error despite correct arguments

I got this code from this link : Reboot with and without glibc

#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#ifdef NO_GLIBC
#include <linux/reboot.h>
#else
#include <sys/reboot.h>
#endif

#ifdef NO_GLIBC
#ifndef LINUX_REBOOT_MAGIC1
#define LINUX_REBOOT_MAGIC1 0xfee1dead
#endif

#ifndef LINUX_REBOOT_MAGIC2
#define LINUX_REBOOT_MAGIC2 0x28121969
#endif

#ifndef LINUX_REBOOT_MAGIC2A
#define LINUX_REBOOT_MAGIC2A 0x05121996
#endif

#ifndef LINUX_REBOOT_MAGIC2B
#define LINUX_REBOOT_MAGIC2B 0x16041998
#endif

#ifndef LINUX_REBOOT_MAGIC2C
#define LINUX_REBOOT_MAGIC2C 0x20112000
#endif
#endif /* NO_GLIBC */

#ifndef LINUX_REBOOT_CMD_RESTART
#define LINUX_REBOOT_CMD_RESTART 0x1234567
#endif

#ifndef LINUX_REBOOT_CMD_HALT
#define LINUX_REBOOT_CMD_HALT 0xcdef0123
#endif

#ifndef LINUX_REBOOT_CMD_POWER_OFF
#define LINUX_REBOOT_CMD_POWER_OFF 0x4321fedc
#endif

#ifndef LINUX_REBOOT_CMD_RESTART2
#define LINUX_REBOOT_CMD_RESTART2 0xa1b3c3d4
#endif

#ifndef LINUX_REBOOT_CMD_CAD_ON
#define LINUX_REBOOT_CMD_CAD_ON 0x89abcdef
#endif

#ifndef LINUX_REBOOT_CMD_CAD_OFF
#define LINUX_REBOOT_CMD_CAD_OFF 0x00000000
#endif

static void do_reboot(int command);

int
main(int argc, char *argv[]) {
int reboot_command;

if(argc == 1) {
fprintf(stderr, "No command given.\n");
fprintf(stderr, "Commands: RESTART, HALT, POWER_OFF, CAD_ON,
CAD_OFF.\n");
return(2);
} else if(strcasecmp(argv[1], "RESTART") == 0) {
reboot_command = LINUX_REBOOT_CMD_RESTART;
} else if(strcasecmp(argv[1], "HALT") == 0) {
reboot_command = LINUX_REBOOT_CMD_HALT;
} else if(strcasecmp(argv[1], "POWER_OFF") == 0) {
reboot_command = LINUX_REBOOT_CMD_POWER_OFF;
} else if(strcasecmp(argv[1], "RESTART2") == 0) {
fprintf(stderr, "RESTART2 not supported. Try RESTART.\n");
return(1);
} else if(strcasecmp(argv[1], "CAD_ON") == 0) {
reboot_command = LINUX_REBOOT_CMD_CAD_ON;
} else if(strcasecmp(argv[1], "CAD_OFF") == 0) {
reboot_command = LINUX_REBOOT_CMD_CAD_OFF;
} else {
fprintf(stderr, "%s not supported.\n", argv[1]);
fprintf(stderr, "Commands: RESTART, HALT, POWER_OFF, CAD_ON,
CAD_OFF.\n");
return(2);
}

do_reboot(reboot_command);

// Not reached, unless command was CAD_ON or CAD_OFF.
return(0);
}

static void
do_reboot(int cmd) {
int reboot_status = 0;

// Flush filesystem buffers before rebooting.
sync();

#ifdef NO_GLIBC
// Old libc.
reboot_status = reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd,
NULL);
#else
// glibc uses a wrapper around the system call.
reboot_status = reboot(cmd);
#endif

if(reboot_status == -1) {
if(errno == EPERM) {
fprintf(stderr, "Permission denied. Are you root?\n");
}
}
}

From this code, we can understand that the format for reboot in oldlibc is :

int reboot(int magic, int magic2, unsigned int cmd, void *arg);

and the format for reboot in glibc is : int reboot(int cmd);

Reason for Error 22: This error implies "Invalid argument" (EINVAL). glibc expects single argument in reboot(int cmd) function call ( glibc uses a wrapper around the system call), but we are giving multiple arguments. That's the reason for the error.

Please see the function call in the above code :

#ifdef NO_GLIBC
// Old libc.
reboot_status = reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd,
NULL);
#else
// glibc uses a wrapper around the system call.
reboot_status = reboot(cmd);
#endif

What do the numbers after command and system call names mean in *nix?

These numbers refer to Unix man sections.

1   Commands available to users
2 Unix and C system calls
3 C library routines for C programs
4 Special file names
5 File formats and conventions for files used by Unix
6 Games
7 Word processing packages
8 System administration commands and procedures

You can specify a section number with the man command by just listing the section number:

man 1 somecommand  

would look for somecommand in section 1 of the man pages.

Wikipedia has some additional information on this as does this page on how to use man pages.

How to define a system call in Linux with non-default return type?

Returning long is the only proper way for a system call in Linux.

There is no way for a system call to return a value, which size differs from the size of long.

Do you expect ssize_t to have the same size as long on all platforms? If yes (this is a correct expectation), then there is no reason to prefer ssize_t over long. If you are not sure that your return type will fit to long on every platform, then you simply cannot use this return type.

For example, from the C standard you knows, that read function returns ssize_t. But read system call has long as return type (it is defined using DEFINE_SYSCALL macro):

SYSCALL_DEFINE3(read, unsigned int, fd, char __user *, buf, size_t, count)
{
struct fd f = fdget(fd);
ssize_t ret = -EBADF;

if (f.file) {
loff_t pos = file_pos_read(f.file);
ret = vfs_read(f.file, buf, count, &pos);
file_pos_write(f.file, pos);
fdput(f);
}
return ret;
}

Note, that despite on long being return type of the system call, the above implementation returns a value of type ssize_t.



Related Topics



Leave a reply



Submit