aboutsummaryrefslogtreecommitdiff
path: root/util-linux
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2006-12-27 04:35:04 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2006-12-27 04:35:04 +0000
commit8d42f86b146871ae4c4cafd3801a85f381249a14 (patch)
treeb963999fc54eddb65f1929b894f868e24851fc9c /util-linux
downloadbusybox-w32-8d42f86b146871ae4c4cafd3801a85f381249a14.tar.gz
busybox-w32-8d42f86b146871ae4c4cafd3801a85f381249a14.tar.bz2
busybox-w32-8d42f86b146871ae4c4cafd3801a85f381249a14.zip
Correcting branch name to be like previous ones
Diffstat (limited to 'util-linux')
-rw-r--r--util-linux/Config.in526
-rw-r--r--util-linux/Kbuild32
-rw-r--r--util-linux/dmesg.c53
-rw-r--r--util-linux/fbset.c407
-rw-r--r--util-linux/fdformat.c143
-rw-r--r--util-linux/fdisk.c3043
-rw-r--r--util-linux/fdisk_aix.c76
-rw-r--r--util-linux/fdisk_osf.c1046
-rw-r--r--util-linux/fdisk_sgi.c885
-rw-r--r--util-linux/fdisk_sun.c729
-rw-r--r--util-linux/freeramdisk.c34
-rw-r--r--util-linux/fsck_minix.c1417
-rw-r--r--util-linux/getopt.c365
-rw-r--r--util-linux/hexdump.c101
-rw-r--r--util-linux/hwclock.c213
-rw-r--r--util-linux/ipcrm.c217
-rw-r--r--util-linux/ipcs.c630
-rw-r--r--util-linux/losetup.c64
-rw-r--r--util-linux/mdev.c268
-rw-r--r--util-linux/mkfs_minix.c762
-rw-r--r--util-linux/mkswap.c47
-rw-r--r--util-linux/more.c177
-rw-r--r--util-linux/mount.c1712
-rw-r--r--util-linux/pivot_root.c24
-rw-r--r--util-linux/rdate.c86
-rw-r--r--util-linux/readprofile.c236
-rw-r--r--util-linux/setarch.c52
-rw-r--r--util-linux/swaponoff.c77
-rw-r--r--util-linux/switch_root.c122
-rw-r--r--util-linux/umount.c151
30 files changed, 13695 insertions, 0 deletions
diff --git a/util-linux/Config.in b/util-linux/Config.in
new file mode 100644
index 000000000..848914d6f
--- /dev/null
+++ b/util-linux/Config.in
@@ -0,0 +1,526 @@
1#
2# For a description of the syntax of this configuration file,
3# see scripts/kbuild/config-language.txt.
4#
5
6menu "Linux System Utilities"
7
8config DMESG
9 bool "dmesg"
10 default n
11 help
12 dmesg is used to examine or control the kernel ring buffer. When the
13 Linux kernel prints messages to the system log, they are stored in
14 the kernel ring buffer. You can use dmesg to print the kernel's ring
15 buffer, clear the kernel ring buffer, change the size of the kernel
16 ring buffer, and change the priority level at which kernel messages
17 are also logged to the system console. Enable this option if you
18 wish to enable the 'dmesg' utility.
19
20config FEATURE_DMESG_PRETTY
21 bool "pretty dmesg output"
22 default y
23 depends on DMESG
24 help
25 If you wish to scrub the syslog level from the output, say 'Y' here.
26 The syslog level is a string prefixed to every line with the form "<#>".
27
28 With this option you will see:
29 # dmesg
30 Linux version 2.6.17.4 .....
31 BIOS-provided physical RAM map:
32 BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
33
34 Without this option you will see:
35 # dmesg
36 <5>Linux version 2.6.17.4 .....
37 <6>BIOS-provided physical RAM map:
38 <6> BIOS-e820: 0000000000000000 - 000000000009f000 (usable)
39
40config FBSET
41 bool "fbset"
42 default n
43 help
44 fbset is used to show or change the settings of a Linux frame buffer
45 device. The frame buffer device provides a simple and unique
46 interface to access a graphics display. Enable this option
47 if you wish to enable the 'fbset' utility.
48
49config FEATURE_FBSET_FANCY
50 bool "Turn on extra fbset options"
51 default n
52 depends on FBSET
53 help
54 This option enables extended fbset options, allowing one to set the
55 framebuffer size, color depth, etc. interface to access a graphics
56 display. Enable this option if you wish to enable extended fbset
57 options.
58
59config FEATURE_FBSET_READMODE
60 bool "Turn on fbset readmode support"
61 default n
62 depends on FBSET
63 help
64 This option allows fbset to read the video mode database stored by
65 default as /etc/fb.modes, which can be used to set frame buffer
66 device to pre-defined video modes.
67
68config FDFLUSH
69 bool "fdflush"
70 default n
71 help
72 fdflush is only needed when changing media on slightly-broken
73 removable media drives. It is used to make Linux believe that a
74 hardware disk-change switch has been actuated, which causes Linux to
75 forget anything it has cached from the previous media. If you have
76 such a slightly-broken drive, you will need to run fdflush every time
77 you change a disk. Most people have working hardware and can safely
78 leave this disabled.
79
80config FDFORMAT
81 bool "fdformat"
82 default n
83 help
84 fdformat is used to low-level format a floppy disk.
85
86config FDISK
87 bool "fdisk"
88 default n
89 help
90 The fdisk utility is used to divide hard disks into one or more
91 logical disks, which are generally called partitions. This utility
92 can be used to list and edit the set of partitions or BSD style
93 'disk slices' that are defined on a hard drive.
94
95config FDISK_SUPPORT_LARGE_DISKS
96 bool "support over 4GB disks"
97 default y
98 depends on FDISK
99 help
100 Enable this option to support large disks > 4GB.
101
102config FEATURE_FDISK_WRITABLE
103 bool "Write support"
104 default y
105 depends on FDISK
106 help
107 Enabling this option allows you to create or change a partition table
108 and write those changes out to disk. If you leave this option
109 disabled, you will only be able to view the partition table.
110
111config FEATURE_AIX_LABEL
112 bool "Support AIX disklabels"
113 default n
114 depends on FDISK && FEATURE_FDISK_WRITABLE
115 help
116 Enabling this option allows you to create or change AIX disklabels.
117 Most people can safely leave this option disabled.
118
119config FEATURE_SGI_LABEL
120 bool "Support SGI disklabels"
121 default n
122 depends on FDISK && FEATURE_FDISK_WRITABLE
123 help
124 Enabling this option allows you to create or change SGI disklabels.
125 Most people can safely leave this option disabled.
126
127config FEATURE_SUN_LABEL
128 bool "Support SUN disklabels"
129 default n
130 depends on FDISK && FEATURE_FDISK_WRITABLE
131 help
132 Enabling this option allows you to create or change SUN disklabels.
133 Most people can safely leave this option disabled.
134
135config FEATURE_OSF_LABEL
136 bool "Support BSD disklabels"
137 default n
138 depends on FDISK && FEATURE_FDISK_WRITABLE
139 help
140 Enabling this option allows you to create or change BSD disklabels
141 and define and edit BSD disk slices.
142
143config FEATURE_FDISK_ADVANCED
144 bool "Support expert mode"
145 default n
146 depends on FDISK && FEATURE_FDISK_WRITABLE
147 help
148 Enabling this option allows you to do terribly unsafe things like
149 define arbitrary drive geometry, move the beginning of data in a
150 partition, and similarly evil things. Unless you have a very good
151 reason you would be wise to leave this disabled.
152
153config FREERAMDISK
154 bool "freeramdisk"
155 default n
156 help
157 Linux allows you to create ramdisks. This utility allows you to
158 delete them and completely free all memory that was used for the
159 ramdisk. For example, if you boot Linux into a ramdisk and later
160 pivot_root, you may want to free the memory that is allocated to the
161 ramdisk. If you have no use for freeing memory from a ramdisk, leave
162 this disabled.
163
164config FSCK_MINIX
165 bool "fsck_minix"
166 default n
167 help
168 The minix filesystem is a nice, small, compact, read-write filesystem
169 with little overhead. It is not a journaling filesystem however and
170 can experience corruption if it is not properly unmounted or if the
171 power goes off in the middle of a write. This utility allows you to
172 check for and attempt to repair any corruption that occurs to a minix
173 filesystem.
174
175config MKFS_MINIX
176 bool "mkfs_minix"
177 default n
178 help
179 The minix filesystem is a nice, small, compact, read-write filesystem
180 with little overhead. If you wish to be able to create minix filesystems
181 this utility will do the job for you.
182
183comment "Minix filesystem support"
184 depends on FSCK_MINIX || MKFS_MINIX
185
186config FEATURE_MINIX2
187 bool "Support Minix fs v2 (fsck_minix/mkfs_minix)"
188 default y
189 depends on FSCK_MINIX || MKFS_MINIX
190 help
191 If you wish to be able to create version 2 minix filesystems, enable this.
192 If you enabled 'mkfs_minix' then you almost certainly want to be using the
193 version 2 filesystem support.
194
195config GETOPT
196 bool "getopt"
197 default n
198 help
199 The getopt utility is used to break up (parse) options in command
200 lines to make it easy to write complex shell scripts that also check
201 for legal (and illegal) options. If you want to write horribly
202 complex shell scripts, or use some horribly complex shell script
203 written by others, this utility may be for you. Most people will
204 wisely leave this disabled.
205
206config HEXDUMP
207 bool "hexdump"
208 default n
209 help
210 The hexdump utility is used to display binary data in a readable
211 way that is comparable to the output from most hex editors.
212
213config HWCLOCK
214 bool "hwclock"
215 default n
216 help
217 The hwclock utility is used to read and set the hardware clock
218 on a system. This is primarily used to set the current time on
219 shutdown in the hardware clock, so the hardware will keep the
220 correct time when Linux is _not_ running.
221
222config FEATURE_HWCLOCK_LONG_OPTIONS
223 bool "Support long options (--hctosys,...)"
224 default n
225 depends on HWCLOCK && GETOPT_LONG
226 help
227 By default, the hwclock utility only uses short options. If you
228 are overly fond of its long options, such as --hctosys, --utc, etc)
229 then enable this option.
230
231config FEATURE_HWCLOCK_ADJTIME_FHS
232 bool "Use FHS /var/lib/hwclock/adjtime"
233 default y
234 depends on HWCLOCK
235 help
236 Starting with FHS 2.3, the adjtime state file is supposed to exist
237 at /var/lib/hwclock/adjtime instead of /etc/adjtime. If you wish
238 to use the FHS behavior, answer Y here, otherwise answer N for the
239 classic /etc/adjtime path.
240
241 http://www.pathname.com/fhs/pub/fhs-2.3.html#VARLIBHWCLOCKSTATEDIRECTORYFORHWCLO
242
243config IPCRM
244 bool "ipcrm"
245 default n
246 select FEATURE_SUID
247 help
248 The ipcrm utility allows the removal of System V interprocess
249 communication (IPC) objects and the associated data structures
250 from the system.
251
252config IPCS
253 bool "ipcs"
254 default n
255 select FEATURE_SUID
256 help
257 The ipcs utility is used to provide information on the currently
258 allocated System V interprocess (IPC) objects in the system.
259
260config LOSETUP
261 bool "losetup"
262 default n
263 help
264 losetup is used to associate or detach a loop device with a regular
265 file or block device, and to query the status of a loop device. This
266 version does not currently support enabling data encryption.
267
268config MDEV
269 bool "mdev"
270 default n
271 help
272 mdev is a mini-udev implementation: call it with -s to populate
273 /dev from /sys, then "echo /sbin/mdev > /proc/sys/kernel/hotplug" to
274 have it handle hotplug events afterwards. Device names are taken
275 from sysfs.
276
277config FEATURE_MDEV_CONF
278 bool "Support /etc/mdev.conf"
279 default n
280 depends on MDEV
281 help
282 The mdev config file contains lines that look like:
283
284 hd[a-z][0-9]* 0:3 660
285
286 That's device name (with regex match), uid:gid, and permissions.
287
288 Config file parsing stops on the first matching line. If no config
289 entry is matched, devices are created with default 0:0 660. (Make
290 the last line match .* to override this.)
291
292config FEATURE_MDEV_EXEC
293 bool "Support command execution at device addition/removal"
294 default n
295 depends on FEATURE_MDEV_CONF
296 help
297 This adds support for an optional field to /etc/mdev.conf, consisting
298 of a special character and a command line to run after creating the
299 corresponding device(s) and before removing, ala:
300
301 hdc root:cdrom 660 *ln -s $MDEV cdrom
302
303 The $MDEV environment variable is set to the name of the device.
304
305 The special characters and their meanings are:
306 @ Run after creating the device.
307 $ Run before removing the device.
308 * Run both after creating and before removing the device.
309
310 Commands are executed via system() so you need /bin/sh, meaning you
311 probably want to select a default shell in the Shells menu.
312
313config MKSWAP
314 bool "mkswap"
315 default n
316 help
317 The mkswap utility is used to configure a file or disk partition as
318 Linux swap space. This allows Linux to use the entire file or
319 partition as if it were additional RAM, which can greatly increase
320 the capability of low-memory machines. This additional memory is
321 much slower than real RAM, but can be very helpful at preventing your
322 applications being killed by the Linux out of memory (OOM) killer.
323 Once you have created swap space using 'mkswap' you need to enable
324 the swap space using the 'swapon' utility.
325
326config FEATURE_MKSWAP_V0
327 bool "version 0 support"
328 default n
329 depends on MKSWAP
330# depends on MKSWAP && DEPRECATED
331 help
332 Enable support for the old v0 style.
333 If your kernel is older than 2.1.117, then v0 support is the
334 only option.
335
336config MORE
337 bool "more"
338 default n
339 help
340 more is a simple utility which allows you to read text one screen
341 sized page at a time. If you want to read text that is larger than
342 the screen, and you are using anything faster than a 300 baud modem,
343 you will probably find this utility very helpful. If you don't have
344 any need to reading text files, you can leave this disabled.
345
346config FEATURE_USE_TERMIOS
347 bool "Use termios to manipulate the screen"
348 default y
349 depends on MORE
350 help
351 This option allows utilities such as 'more' and 'top' to determine
352 the size of the screen. If you leave this disabled, your utilities
353 that display things on the screen will be especially primitive and
354 will be unable to determine the current screen size, and will be
355 unable to move the cursor.
356
357config MOUNT
358 bool "mount"
359 default n
360 help
361 All files and filesystems in Unix are arranged into one big directory
362 tree. The 'mount' utility is used to graft a filesystem onto a
363 particular part of the tree. A filesystem can either live on a block
364 device, or it can be accessible over the network, as is the case with
365 NFS filesystems. Most people using BusyBox will also want to enable
366 the 'mount' utility.
367
368config FEATURE_MOUNT_NFS
369 bool "Support mounting NFS file systems"
370 default n
371 depends on MOUNT
372 depends on FEATURE_HAVE_RPC
373 select FEATURE_SYSLOG
374 help
375 Enable mounting of NFS file systems.
376
377config FEATURE_MOUNT_CIFS
378 bool "Support mounting CIFS/SMB file systems"
379 default n
380 depends on MOUNT
381 help
382 Enable support for samba mounts.
383
384config FEATURE_MOUNT_FLAGS
385 depends on MOUNT
386 bool "Support lots of -o flags in mount"
387 default y
388 help
389 Without this, mount only supports ro/rw/remount. With this, it
390 supports nosuid, suid, dev, nodev, exec, noexec, sync, async, atime,
391 noatime, diratime, nodiratime, loud, bind, move, shared, slave,
392 private, unbindable, rshared, rslave, rprivate, and runbindable.
393
394config FEATURE_MOUNT_FSTAB
395 depends on MOUNT
396 bool "Support /etc/fstab and -a"
397 default y
398 help
399 Support mount all and looking for files in /etc/fstab.
400
401config PIVOT_ROOT
402 bool "pivot_root"
403 default n
404 help
405 The pivot_root utility swaps the mount points for the root filesystem
406 with some other mounted filesystem. This allows you to do all sorts
407 of wild and crazy things with your Linux system and is far more
408 powerful than 'chroot'.
409
410 Note: This is for initrd in linux 2.4. Under initramfs (introduced
411 in linux 2.6) use switch_root instead.
412
413config RDATE
414 bool "rdate"
415 default n
416 help
417 The rdate utility allows you to synchronize the date and time of your
418 system clock with the date and time of a remote networked system using
419 the RFC868 protocol, which is built into the inetd daemon on most
420 systems.
421
422config READPROFILE
423 bool "readprofile"
424 default n
425 help
426 This allows you to parse /proc/profile for basic profiling.
427
428config SETARCH
429 bool "setarch"
430 default n
431 help
432 The linux32 utility is used to create a 32bit environment for the
433 specified program (usually a shell). It only makes sense to have
434 this util on a system that supports both 64bit and 32bit userland
435 (like amd64/x86, ppc64/ppc, sparc64/sparc, etc...).
436
437config SWAPONOFF
438 bool "swaponoff"
439 default n
440 help
441 This option enables both the 'swapon' and the 'swapoff' utilities.
442 Once you have created some swap space using 'mkswap', you also need
443 to enable your swap space with the 'swapon' utility. The 'swapoff'
444 utility is used, typically at system shutdown, to disable any swap
445 space. If you are not using any swap space, you can leave this
446 option disabled.
447
448config SWITCH_ROOT
449 bool "switch_root"
450 default n
451 help
452 The switch_root utility is used from initramfs to select a new
453 root device. Under initramfs, you have to use this instead of
454 pivot_root. (Stop reading here if you don't care why.)
455
456 Booting with initramfs extracts a gzipped cpio archive into rootfs
457 (which is a variant of ramfs/tmpfs). Because rootfs can't be moved
458 or unmounted*, pivot_root will not work from initramfs. Instead,
459 switch_root deletes everything out of rootfs (including itself),
460 does a mount --move that overmounts rootfs with the new root, and
461 then execs the specified init program.
462
463 * Because the Linux kernel uses rootfs internally as the starting
464 and ending point for searching through the kernel's doubly linked
465 list of active mount points. That's why.
466
467config UMOUNT
468 bool "umount"
469 default n
470 help
471 When you want to remove a mounted filesystem from its current mount point,
472 for example when you are shutting down the system, the 'umount' utility is
473 the tool to use. If you enabled the 'mount' utility, you almost certainly
474 also want to enable 'umount'.
475
476config FEATURE_UMOUNT_ALL
477 bool "umount -a option"
478 default n
479 depends on UMOUNT
480 help
481 Support -a option to unmount all currently mounted filesystems.
482
483comment "Common options for mount/umount"
484 depends on MOUNT || UMOUNT
485
486config FEATURE_MOUNT_LOOP
487 bool "Support loopback mounts"
488 default n
489 depends on MOUNT || UMOUNT
490 help
491 Enabling this feature allows automatic mounting of files (containing
492 filesystem images) via the linux kernel's loopback devices. The mount
493 command will detect you are trying to mount a file instead of a block
494 device, and transparently associate the file with a loopback device.
495 The umount command will also free that loopback device.
496
497 You can still use the 'losetup' utility (to manually associate files
498 with loop devices) if you need to do something advanced, such as
499 specify an offset or cryptographic options to the loopback device.
500 (If you don't want umount to free the loop device, use "umount -D".)
501
502config FEATURE_MTAB_SUPPORT
503 bool "Support for the old /etc/mtab file"
504 default n
505 depends on MOUNT || UMOUNT
506 help
507 Historically, Unix systems kept track of the currently mounted
508 partitions in the file "/etc/mtab". These days, the kernel exports
509 the list of currently mounted partitions in "/proc/mounts", rendering
510 the old mtab file obsolete. (In modern systems, /etc/mtab should be
511 a symlink to /proc/mounts.)
512
513 The only reason to have mount maintain an /etc/mtab file itself is if
514 your stripped-down embedded system does not have a /proc directory.
515 If you must use this, keep in mind it's inherently brittle (for
516 example a mount under chroot won't update it), can't handle modern
517 features like separate per-process filesystem namespaces, requires
518 that your /etc directory be writeable, tends to get easily confused
519 by --bind or --move mounts, won't update if you rename a directory
520 that contains a mount point, and so on. (In brief: avoid.)
521
522 About the only reason to use this is if you've removed /proc from
523 your kernel.
524
525endmenu
526
diff --git a/util-linux/Kbuild b/util-linux/Kbuild
new file mode 100644
index 000000000..cc1d0e05d
--- /dev/null
+++ b/util-linux/Kbuild
@@ -0,0 +1,32 @@
1# Makefile for busybox
2#
3# Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
4#
5# Licensed under the GPL v2, see the file LICENSE in this tarball.
6
7lib-y:=
8lib-$(CONFIG_DMESG) +=dmesg.o
9lib-$(CONFIG_FBSET) +=fbset.o
10lib-$(CONFIG_FDFLUSH) +=freeramdisk.o
11lib-$(CONFIG_FDFORMAT) +=fdformat.o
12lib-$(CONFIG_FDISK) +=fdisk.o
13lib-$(CONFIG_FREERAMDISK) +=freeramdisk.o
14lib-$(CONFIG_FSCK_MINIX) +=fsck_minix.o
15lib-$(CONFIG_GETOPT) +=getopt.o
16lib-$(CONFIG_HEXDUMP) +=hexdump.o
17lib-$(CONFIG_HWCLOCK) +=hwclock.o
18lib-$(CONFIG_IPCRM) +=ipcrm.o
19lib-$(CONFIG_IPCS) +=ipcs.o
20lib-$(CONFIG_LOSETUP) +=losetup.o
21lib-$(CONFIG_MDEV) +=mdev.o
22lib-$(CONFIG_MKFS_MINIX) +=mkfs_minix.o
23lib-$(CONFIG_MKSWAP) +=mkswap.o
24lib-$(CONFIG_MORE) +=more.o
25lib-$(CONFIG_MOUNT) +=mount.o
26lib-$(CONFIG_PIVOT_ROOT) +=pivot_root.o
27lib-$(CONFIG_RDATE) +=rdate.o
28lib-$(CONFIG_READPROFILE) +=readprofile.o
29lib-$(CONFIG_SETARCH) +=setarch.o
30lib-$(CONFIG_SWAPONOFF) +=swaponoff.o
31lib-$(CONFIG_SWITCH_ROOT) +=switch_root.o
32lib-$(CONFIG_UMOUNT) +=umount.o
diff --git a/util-linux/dmesg.c b/util-linux/dmesg.c
new file mode 100644
index 000000000..658cddc38
--- /dev/null
+++ b/util-linux/dmesg.c
@@ -0,0 +1,53 @@
1/* vi: set sw=4 ts=4: */
2/*
3 *
4 * dmesg - display/control kernel ring buffer.
5 *
6 * Copyright 2006 Rob Landley <rob@landley.net>
7 * Copyright 2006 Bernhard Fischer <rep.nop@aon.at>
8 *
9 * Licensed under GPLv2, see file LICENSE in this tarball for details.
10 */
11
12#include "busybox.h"
13#include <unistd.h>
14#include <sys/klog.h>
15
16int dmesg_main(int argc, char *argv[])
17{
18 char *size, *level;
19 int flags = getopt32(argc, argv, "cs:n:", &size, &level);
20
21 if (flags & 4) {
22 if (klogctl(8, NULL, xatoul_range(level, 0, 10)))
23 bb_perror_msg_and_die("klogctl");
24 } else {
25 int len;
26 char *buf;
27
28 len = (flags & 2) ? xatoul_range(size, 2, INT_MAX) : 16384;
29 buf = xmalloc(len);
30 if (0 > (len = klogctl(3 + (flags & 1), buf, len)))
31 bb_perror_msg_and_die("klogctl");
32
33 // Skip <#> at the start of lines, and make sure we end with a newline.
34
35 if (ENABLE_FEATURE_DMESG_PRETTY) {
36 int last = '\n';
37 int in;
38
39 for (in = 0; in<len;) {
40 if (last == '\n' && buf[in] == '<') in += 3;
41 else putchar(last = buf[in++]);
42 }
43 if (last != '\n') putchar('\n');
44 } else {
45 write(1,buf,len);
46 if (len && buf[len-1]!='\n') putchar('\n');
47 }
48
49 if (ENABLE_FEATURE_CLEAN_UP) free(buf);
50 }
51
52 return 0;
53}
diff --git a/util-linux/fbset.c b/util-linux/fbset.c
new file mode 100644
index 000000000..1aa0a0ac1
--- /dev/null
+++ b/util-linux/fbset.c
@@ -0,0 +1,407 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini fbset implementation for busybox
4 *
5 * Copyright (C) 1999 by Randolph Chung <tausq@debian.org>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 *
9 * This is a from-scratch implementation of fbset; but the de facto fbset
10 * implementation was a good reference. fbset (original) is released under
11 * the GPL, and is (c) 1995-1999 by:
12 * Geert Uytterhoeven (Geert.Uytterhoeven@cs.kuleuven.ac.be)
13 */
14
15#include "busybox.h"
16
17#define DEFAULTFBDEV FB_0
18#define DEFAULTFBMODE "/etc/fb.modes"
19
20enum {
21 OPT_CHANGE = (1 << 0),
22 OPT_INFO = (1 << 1),
23 OPT_READMODE = (1 << 2),
24 OPT_ALL = (1 << 9),
25
26 CMD_FB = 1,
27 CMD_DB = 2,
28 CMD_GEOMETRY = 3,
29 CMD_TIMING = 4,
30 CMD_ACCEL = 5,
31 CMD_HSYNC = 6,
32 CMD_VSYNC = 7,
33 CMD_LACED = 8,
34 CMD_DOUBLE = 9,
35/* CMD_XCOMPAT = 10, */
36 CMD_ALL = 11,
37 CMD_INFO = 12,
38 CMD_CHANGE = 13,
39
40#ifdef CONFIG_FEATURE_FBSET_FANCY
41 CMD_XRES = 100,
42 CMD_YRES = 101,
43 CMD_VXRES = 102,
44 CMD_VYRES = 103,
45 CMD_DEPTH = 104,
46 CMD_MATCH = 105,
47 CMD_PIXCLOCK = 106,
48 CMD_LEFT = 107,
49 CMD_RIGHT = 108,
50 CMD_UPPER = 109,
51 CMD_LOWER = 110,
52 CMD_HSLEN = 111,
53 CMD_VSLEN = 112,
54 CMD_CSYNC = 113,
55 CMD_GSYNC = 114,
56 CMD_EXTSYNC = 115,
57 CMD_BCAST = 116,
58 CMD_RGBA = 117,
59 CMD_STEP = 118,
60 CMD_MOVE = 119,
61#endif
62};
63
64static unsigned int g_options = 0;
65
66/* Stuff stolen from the kernel's fb.h */
67#define FB_ACTIVATE_ALL 64
68enum {
69 FBIOGET_VSCREENINFO = 0x4600,
70 FBIOPUT_VSCREENINFO = 0x4601
71};
72struct fb_bitfield {
73 uint32_t offset; /* beginning of bitfield */
74 uint32_t length; /* length of bitfield */
75 uint32_t msb_right; /* !=0: Most significant bit is right */
76};
77struct fb_var_screeninfo {
78 uint32_t xres; /* visible resolution */
79 uint32_t yres;
80 uint32_t xres_virtual; /* virtual resolution */
81 uint32_t yres_virtual;
82 uint32_t xoffset; /* offset from virtual to visible */
83 uint32_t yoffset; /* resolution */
84
85 uint32_t bits_per_pixel;
86 uint32_t grayscale; /* !=0 Graylevels instead of colors */
87
88 struct fb_bitfield red; /* bitfield in fb mem if true color, */
89 struct fb_bitfield green; /* else only length is significant */
90 struct fb_bitfield blue;
91 struct fb_bitfield transp; /* transparency */
92
93 uint32_t nonstd; /* !=0 Non standard pixel format */
94
95 uint32_t activate; /* see FB_ACTIVATE_x */
96
97 uint32_t height; /* height of picture in mm */
98 uint32_t width; /* width of picture in mm */
99
100 uint32_t accel_flags; /* acceleration flags (hints) */
101
102 /* Timing: All values in pixclocks, except pixclock (of course) */
103 uint32_t pixclock; /* pixel clock in ps (pico seconds) */
104 uint32_t left_margin; /* time from sync to picture */
105 uint32_t right_margin; /* time from picture to sync */
106 uint32_t upper_margin; /* time from sync to picture */
107 uint32_t lower_margin;
108 uint32_t hsync_len; /* length of horizontal sync */
109 uint32_t vsync_len; /* length of vertical sync */
110 uint32_t sync; /* see FB_SYNC_x */
111 uint32_t vmode; /* see FB_VMODE_x */
112 uint32_t reserved[6]; /* Reserved for future compatibility */
113};
114
115
116static const struct cmdoptions_t {
117 const char name[10];
118 const unsigned char param_count;
119 const unsigned char code;
120} g_cmdoptions[] = {
121 { "-fb", 1, CMD_FB },
122 { "-db", 1, CMD_DB },
123 { "-a", 0, CMD_ALL },
124 { "-i", 0, CMD_INFO },
125 { "-g", 5, CMD_GEOMETRY },
126 { "-t", 7, CMD_TIMING },
127 { "-accel", 1, CMD_ACCEL },
128 { "-hsync", 1, CMD_HSYNC },
129 { "-vsync", 1, CMD_VSYNC },
130 { "-laced", 1, CMD_LACED },
131 { "-double", 1, CMD_DOUBLE },
132 { "-n", 0, CMD_CHANGE },
133#ifdef CONFIG_FEATURE_FBSET_FANCY
134 { "-all", 0, CMD_ALL },
135 { "-xres", 1, CMD_XRES },
136 { "-yres", 1, CMD_YRES },
137 { "-vxres", 1, CMD_VXRES },
138 { "-vyres", 1, CMD_VYRES },
139 { "-depth", 1, CMD_DEPTH },
140 { "-match", 0, CMD_MATCH },
141 { "-geometry", 5, CMD_GEOMETRY },
142 { "-pixclock", 1, CMD_PIXCLOCK },
143 { "-left", 1, CMD_LEFT },
144 { "-right", 1, CMD_RIGHT },
145 { "-upper", 1, CMD_UPPER },
146 { "-lower", 1, CMD_LOWER },
147 { "-hslen", 1, CMD_HSLEN },
148 { "-vslen", 1, CMD_VSLEN },
149 { "-timings", 7, CMD_TIMING },
150 { "-csync", 1, CMD_CSYNC },
151 { "-gsync", 1, CMD_GSYNC },
152 { "-extsync", 1, CMD_EXTSYNC },
153 { "-bcast", 1, CMD_BCAST },
154 { "-rgba", 1, CMD_RGBA },
155 { "-step", 1, CMD_STEP },
156 { "-move", 1, CMD_MOVE },
157#endif
158 { "", 0, 0 }
159};
160
161#ifdef CONFIG_FEATURE_FBSET_READMODE
162/* taken from linux/fb.h */
163enum {
164 FB_VMODE_INTERLACED = 1, /* interlaced */
165 FB_VMODE_DOUBLE = 2, /* double scan */
166 FB_SYNC_HOR_HIGH_ACT = 1, /* horizontal sync high active */
167 FB_SYNC_VERT_HIGH_ACT = 2, /* vertical sync high active */
168 FB_SYNC_EXT = 4, /* external sync */
169 FB_SYNC_COMP_HIGH_ACT = 8 /* composite sync high active */
170};
171#endif
172
173static int readmode(struct fb_var_screeninfo *base, const char *fn,
174 const char *mode)
175{
176#ifdef CONFIG_FEATURE_FBSET_READMODE
177 FILE *f;
178 char buf[256];
179 char *p = buf;
180
181 f = xfopen(fn, "r");
182 while (!feof(f)) {
183 fgets(buf, sizeof(buf), f);
184 if (!(p = strstr(buf, "mode ")) && !(p = strstr(buf, "mode\t")))
185 continue;
186 p += 5;
187 if (!(p = strstr(buf, mode)))
188 continue;
189 p += strlen(mode);
190 if (!isspace(*p) && (*p != 0) && (*p != '"')
191 && (*p != '\r') && (*p != '\n'))
192 continue; /* almost, but not quite */
193
194 while (!feof(f)) {
195 fgets(buf, sizeof(buf), f);
196 if ((p = strstr(buf, "geometry "))) {
197 p += 9;
198 /* FIXME: catastrophic on arches with 64bit ints */
199 sscanf(p, "%d %d %d %d %d",
200 &(base->xres), &(base->yres),
201 &(base->xres_virtual), &(base->yres_virtual),
202 &(base->bits_per_pixel));
203 } else if ((p = strstr(buf, "timings "))) {
204 p += 8;
205 sscanf(p, "%d %d %d %d %d %d %d",
206 &(base->pixclock),
207 &(base->left_margin), &(base->right_margin),
208 &(base->upper_margin), &(base->lower_margin),
209 &(base->hsync_len), &(base->vsync_len));
210 } else if ((p = strstr(buf, "laced "))) {
211 //p += 6;
212 if (strstr(buf, "false")) {
213 base->vmode &= ~FB_VMODE_INTERLACED;
214 } else {
215 base->vmode |= FB_VMODE_INTERLACED;
216 }
217 } else if ((p = strstr(buf, "double "))) {
218 //p += 7;
219 if (strstr(buf, "false")) {
220 base->vmode &= ~FB_VMODE_DOUBLE;
221 } else {
222 base->vmode |= FB_VMODE_DOUBLE;
223 }
224 } else if ((p = strstr(buf, "vsync "))) {
225 //p += 6;
226 if (strstr(buf, "low")) {
227 base->sync &= ~FB_SYNC_VERT_HIGH_ACT;
228 } else {
229 base->sync |= FB_SYNC_VERT_HIGH_ACT;
230 }
231 } else if ((p = strstr(buf, "hsync "))) {
232 //p += 6;
233 if (strstr(buf, "low")) {
234 base->sync &= ~FB_SYNC_HOR_HIGH_ACT;
235 } else {
236 base->sync |= FB_SYNC_HOR_HIGH_ACT;
237 }
238 } else if ((p = strstr(buf, "csync "))) {
239 //p += 6;
240 if (strstr(buf, "low")) {
241 base->sync &= ~FB_SYNC_COMP_HIGH_ACT;
242 } else {
243 base->sync |= FB_SYNC_COMP_HIGH_ACT;
244 }
245 } else if ((p = strstr(buf, "extsync "))) {
246 //p += 8;
247 if (strstr(buf, "false")) {
248 base->sync &= ~FB_SYNC_EXT;
249 } else {
250 base->sync |= FB_SYNC_EXT;
251 }
252 }
253
254 if (strstr(buf, "endmode"))
255 return 1;
256 }
257 }
258#else
259 bb_error_msg("mode reading not compiled in");
260#endif
261 return 0;
262}
263
264static inline void setmode(struct fb_var_screeninfo *base,
265 struct fb_var_screeninfo *set)
266{
267 if ((int) set->xres > 0)
268 base->xres = set->xres;
269 if ((int) set->yres > 0)
270 base->yres = set->yres;
271 if ((int) set->xres_virtual > 0)
272 base->xres_virtual = set->xres_virtual;
273 if ((int) set->yres_virtual > 0)
274 base->yres_virtual = set->yres_virtual;
275 if ((int) set->bits_per_pixel > 0)
276 base->bits_per_pixel = set->bits_per_pixel;
277}
278
279static inline void showmode(struct fb_var_screeninfo *v)
280{
281 double drate = 0, hrate = 0, vrate = 0;
282
283 if (v->pixclock) {
284 drate = 1e12 / v->pixclock;
285 hrate = drate / (v->left_margin + v->xres + v->right_margin + v->hsync_len);
286 vrate = hrate / (v->upper_margin + v->yres + v->lower_margin + v->vsync_len);
287 }
288 printf("\nmode \"%ux%u-%u\"\n"
289#ifdef CONFIG_FEATURE_FBSET_FANCY
290 "\t# D: %.3f MHz, H: %.3f kHz, V: %.3f Hz\n"
291#endif
292 "\tgeometry %u %u %u %u %u\n"
293 "\ttimings %u %u %u %u %u %u %u\n"
294 "\taccel %s\n"
295 "\trgba %u/%u,%u/%u,%u/%u,%u/%u\n"
296 "endmode\n\n",
297 v->xres, v->yres, (int) (vrate + 0.5),
298#ifdef CONFIG_FEATURE_FBSET_FANCY
299 drate / 1e6, hrate / 1e3, vrate,
300#endif
301 v->xres, v->yres, v->xres_virtual, v->yres_virtual, v->bits_per_pixel,
302 v->pixclock, v->left_margin, v->right_margin, v->upper_margin, v->lower_margin,
303 v->hsync_len, v->vsync_len,
304 (v->accel_flags > 0 ? "true" : "false"),
305 v->red.length, v->red.offset, v->green.length, v->green.offset,
306 v->blue.length, v->blue.offset, v->transp.length, v->transp.offset);
307}
308
309#ifdef STANDALONE
310int main(int argc, char **argv)
311#else
312int fbset_main(int argc, char **argv)
313#endif
314{
315 struct fb_var_screeninfo var, varset;
316 int fh, i;
317 char *fbdev = DEFAULTFBDEV;
318 char *modefile = DEFAULTFBMODE;
319 char *thisarg, *mode = NULL;
320
321 memset(&varset, 0xFF, sizeof(varset));
322
323 /* parse cmd args.... why do they have to make things so difficult? */
324 argv++;
325 argc--;
326 for (; argc > 0 && (thisarg = *argv); argc--, argv++) {
327 for (i = 0; g_cmdoptions[i].name[0]; i++) {
328 if (strcmp(thisarg, g_cmdoptions[i].name))
329 continue;
330 if (argc-1 < g_cmdoptions[i].param_count)
331 bb_show_usage();
332
333 switch (g_cmdoptions[i].code) {
334 case CMD_FB:
335 fbdev = argv[1];
336 break;
337 case CMD_DB:
338 modefile = argv[1];
339 break;
340 case CMD_GEOMETRY:
341 varset.xres = xatou32(argv[1]);
342 varset.yres = xatou32(argv[2]);
343 varset.xres_virtual = xatou32(argv[3]);
344 varset.yres_virtual = xatou32(argv[4]);
345 varset.bits_per_pixel = xatou32(argv[5]);
346 break;
347 case CMD_TIMING:
348 varset.pixclock = xatou32(argv[1]);
349 varset.left_margin = xatou32(argv[2]);
350 varset.right_margin = xatou32(argv[3]);
351 varset.upper_margin = xatou32(argv[4]);
352 varset.lower_margin = xatou32(argv[5]);
353 varset.hsync_len = xatou32(argv[6]);
354 varset.vsync_len = xatou32(argv[7]);
355 break;
356 case CMD_ALL:
357 g_options |= OPT_ALL;
358 break;
359 case CMD_CHANGE:
360 g_options |= OPT_CHANGE;
361 break;
362#ifdef CONFIG_FEATURE_FBSET_FANCY
363 case CMD_XRES:
364 varset.xres = xatou32(argv[1]);
365 break;
366 case CMD_YRES:
367 varset.yres = xatou32(argv[1]);
368 break;
369 case CMD_DEPTH:
370 varset.bits_per_pixel = xatou32(argv[1]);
371 break;
372#endif
373 }
374 argc -= g_cmdoptions[i].param_count;
375 argv += g_cmdoptions[i].param_count;
376 break;
377 }
378 if (!g_cmdoptions[i].name[0]) {
379 if (argc != 1)
380 bb_show_usage();
381 mode = *argv;
382 g_options |= OPT_READMODE;
383 }
384 }
385
386 fh = xopen(fbdev, O_RDONLY);
387 if (ioctl(fh, FBIOGET_VSCREENINFO, &var))
388 bb_perror_msg_and_die("ioctl(%sT_VSCREENINFO)", "GE");
389 if (g_options & OPT_READMODE) {
390 if (!readmode(&var, modefile, mode)) {
391 bb_error_msg_and_die("unknown video mode '%s'", mode);
392 }
393 }
394
395 setmode(&var, &varset);
396 if (g_options & OPT_CHANGE) {
397 if (g_options & OPT_ALL)
398 var.activate = FB_ACTIVATE_ALL;
399 if (ioctl(fh, FBIOPUT_VSCREENINFO, &var))
400 bb_perror_msg_and_die("ioctl(%sT_VSCREENINFO)", "PU");
401 }
402 showmode(&var);
403 /* Don't close the file, as exiting will take care of that */
404 /* close(fh); */
405
406 return EXIT_SUCCESS;
407}
diff --git a/util-linux/fdformat.c b/util-linux/fdformat.c
new file mode 100644
index 000000000..0242d8d3a
--- /dev/null
+++ b/util-linux/fdformat.c
@@ -0,0 +1,143 @@
1/* vi: set sw=4 ts=4: */
2/* fdformat.c - Low-level formats a floppy disk - Werner Almesberger */
3
4/* 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
5 * - added Native Language Support
6 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
7 * - more i18n/nls translatable strings marked
8 *
9 * 5 July 2003 -- modified for Busybox by Erik Andersen
10 */
11
12#include "busybox.h"
13
14
15/* Stuff extracted from linux/fd.h */
16struct floppy_struct {
17 unsigned int size, /* nr of sectors total */
18 sect, /* sectors per track */
19 head, /* nr of heads */
20 track, /* nr of tracks */
21 stretch; /* !=0 means double track steps */
22#define FD_STRETCH 1
23#define FD_SWAPSIDES 2
24
25 unsigned char gap, /* gap1 size */
26
27 rate, /* data rate. |= 0x40 for perpendicular */
28#define FD_2M 0x4
29#define FD_SIZECODEMASK 0x38
30#define FD_SIZECODE(floppy) (((((floppy)->rate&FD_SIZECODEMASK)>> 3)+ 2) %8)
31#define FD_SECTSIZE(floppy) ( (floppy)->rate & FD_2M ? \
32 512 : 128 << FD_SIZECODE(floppy) )
33#define FD_PERP 0x40
34
35 spec1, /* stepping rate, head unload time */
36 fmt_gap; /* gap2 size */
37 const char * name; /* used only for predefined formats */
38};
39struct format_descr {
40 unsigned int device,head,track;
41};
42#define FDFMTBEG _IO(2,0x47)
43#define FDFMTTRK _IOW(2,0x48, struct format_descr)
44#define FDFMTEND _IO(2,0x49)
45#define FDGETPRM _IOR(2, 0x04, struct floppy_struct)
46#define FD_FILL_BYTE 0xF6 /* format fill byte. */
47
48static void xioctl(int fd, int request, void *argp, const char *string)
49{
50 if (ioctl(fd, request, argp) < 0) {
51 bb_perror_msg_and_die(string);
52 }
53}
54
55int fdformat_main(int argc,char **argv)
56{
57 int fd, n, cyl, read_bytes, verify;
58 unsigned char *data;
59 struct stat st;
60 struct floppy_struct param;
61 struct format_descr descr;
62
63 if (argc < 2) {
64 bb_show_usage();
65 }
66 verify = !getopt32(argc, argv, "n");
67 argv += optind;
68
69 xstat(*argv, &st);
70 if (!S_ISBLK(st.st_mode)) {
71 bb_error_msg_and_die("%s: not a block device", *argv);
72 /* do not test major - perhaps this was an USB floppy */
73 }
74
75 /* O_RDWR for formatting and verifying */
76 fd = xopen(*argv, O_RDWR);
77
78 /* original message was: "Could not determine current format type" */
79 xioctl(fd, FDGETPRM, &param, "FDGETPRM");
80
81 printf("%s-sided, %d tracks, %d sec/track. Total capacity %d kB\n",
82 (param.head == 2) ? "Double" : "Single",
83 param.track, param.sect, param.size >> 1);
84
85 /* FORMAT */
86 printf("Formatting... ");
87 xioctl(fd, FDFMTBEG, NULL, "FDFMTBEG");
88
89 /* n == track */
90 for (n = 0; n < param.track; n++) {
91 descr.head = 0;
92 descr.track = n;
93 xioctl(fd, FDFMTTRK, &descr, "FDFMTTRK");
94 printf("%3d\b\b\b", n);
95 if (param.head == 2) {
96 descr.head = 1;
97 xioctl(fd, FDFMTTRK, &descr, "FDFMTTRK");
98 }
99 }
100
101 xioctl(fd, FDFMTEND, NULL, "FDFMTEND");
102 printf("done\n");
103
104 /* VERIFY */
105 if (verify) {
106 /* n == cyl_size */
107 n = param.sect*param.head*512;
108
109 data = xmalloc(n);
110 printf("Verifying... ");
111 for (cyl = 0; cyl < param.track; cyl++) {
112 printf("%3d\b\b\b", cyl);
113 read_bytes = safe_read(fd, data, n);
114 if (read_bytes != n) {
115 if (read_bytes < 0) {
116 bb_perror_msg(bb_msg_read_error);
117 }
118 bb_error_msg_and_die("problem reading cylinder %d, "
119 "expected %d, read %d", cyl, n, read_bytes);
120 // FIXME: maybe better seek & continue??
121 }
122 /* Check backwards so we don't need a counter */
123 while (--read_bytes >= 0) {
124 if (data[read_bytes] != FD_FILL_BYTE) {
125 printf("bad data in cyl %d\nContinuing... ",cyl);
126 }
127 }
128 }
129 /* There is no point in freeing blocks at the end of a program, because
130 all of the program's space is given back to the system when the process
131 terminates.*/
132
133 if (ENABLE_FEATURE_CLEAN_UP) free(data);
134
135 printf("done\n");
136 }
137
138 if (ENABLE_FEATURE_CLEAN_UP) close(fd);
139
140 /* Don't bother closing. Exit does
141 * that, so we can save a few bytes */
142 return EXIT_SUCCESS;
143}
diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c
new file mode 100644
index 000000000..2f87f1c60
--- /dev/null
+++ b/util-linux/fdisk.c
@@ -0,0 +1,3043 @@
1/* vi: set sw=4 ts=4: */
2/* fdisk.c -- Partition table manipulator for Linux.
3 *
4 * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk)
5 * Copyright (C) 2001,2002 Vladimir Oleynik <dzo@simtreas.ru> (initial bb port)
6 *
7 * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
8 */
9
10#include <assert.h> /* assert */
11#include "busybox.h"
12#define _(x) x
13
14/* Looks like someone forgot to add this to config system */
15#ifndef ENABLE_FEATURE_FDISK_BLKSIZE
16# define ENABLE_FEATURE_FDISK_BLKSIZE 0
17# define USE_FEATURE_FDISK_BLKSIZE(a)
18#endif
19
20#define DEFAULT_SECTOR_SIZE 512
21#define MAX_SECTOR_SIZE 2048
22#define SECTOR_SIZE 512 /* still used in osf/sgi/sun code */
23#define MAXIMUM_PARTS 60
24
25#define ACTIVE_FLAG 0x80
26
27#define EXTENDED 0x05
28#define WIN98_EXTENDED 0x0f
29#define LINUX_PARTITION 0x81
30#define LINUX_SWAP 0x82
31#define LINUX_NATIVE 0x83
32#define LINUX_EXTENDED 0x85
33#define LINUX_LVM 0x8e
34#define LINUX_RAID 0xfd
35
36#define IS_EXTENDED(i) \
37 ((i) == EXTENDED || (i) == WIN98_EXTENDED || (i) == LINUX_EXTENDED)
38
39#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
40
41#define cround(n) (display_in_cyl_units ? ((n)/units_per_sector)+1 : (n))
42#define scround(x) (((x)+units_per_sector-1)/units_per_sector)
43
44struct hd_geometry {
45 unsigned char heads;
46 unsigned char sectors;
47 unsigned short cylinders;
48 unsigned long start;
49};
50
51#define HDIO_GETGEO 0x0301 /* get device geometry */
52
53struct systypes {
54 const char *name;
55};
56
57static unsigned sector_size = DEFAULT_SECTOR_SIZE;
58static unsigned user_set_sector_size;
59static unsigned sector_offset = 1;
60
61/*
62 * Raw disk label. For DOS-type partition tables the MBR,
63 * with descriptions of the primary partitions.
64 */
65#if (MAX_SECTOR_SIZE) > (BUFSIZ+1)
66static char MBRbuffer[MAX_SECTOR_SIZE];
67#else
68# define MBRbuffer bb_common_bufsiz1
69#endif
70
71#if ENABLE_FEATURE_OSF_LABEL
72static int possibly_osf_label;
73#endif
74
75static unsigned heads, sectors, cylinders;
76static void update_units(void);
77
78
79/*
80 * return partition name - uses static storage unless buf is supplied
81 */
82static const char *
83partname(const char *dev, int pno, int lth)
84{
85 static char buffer[80];
86 const char *p;
87 int w, wp;
88 int bufsiz;
89 char *bufp;
90
91 bufp = buffer;
92 bufsiz = sizeof(buffer);
93
94 w = strlen(dev);
95 p = "";
96
97 if (isdigit(dev[w-1]))
98 p = "p";
99
100 /* devfs kludge - note: fdisk partition names are not supposed
101 to equal kernel names, so there is no reason to do this */
102 if (strcmp(dev + w - 4, "disc") == 0) {
103 w -= 4;
104 p = "part";
105 }
106
107 wp = strlen(p);
108
109 if (lth) {
110 snprintf(bufp, bufsiz, "%*.*s%s%-2u",
111 lth-wp-2, w, dev, p, pno);
112 } else {
113 snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno);
114 }
115 return bufp;
116}
117
118struct partition {
119 unsigned char boot_ind; /* 0x80 - active */
120 unsigned char head; /* starting head */
121 unsigned char sector; /* starting sector */
122 unsigned char cyl; /* starting cylinder */
123 unsigned char sys_ind; /* What partition type */
124 unsigned char end_head; /* end head */
125 unsigned char end_sector; /* end sector */
126 unsigned char end_cyl; /* end cylinder */
127 unsigned char start4[4]; /* starting sector counting from 0 */
128 unsigned char size4[4]; /* nr of sectors in partition */
129} ATTRIBUTE_PACKED;
130
131enum failure {
132 ioctl_error, unable_to_open, unable_to_read, unable_to_seek,
133 unable_to_write
134};
135
136enum label_type {
137 label_dos, label_sun, label_sgi, label_aix, label_osf
138};
139#define LABEL_IS_DOS (label_dos == current_label_type)
140
141#if ENABLE_FEATURE_SUN_LABEL
142#define LABEL_IS_SUN (label_sun == current_label_type)
143#define STATIC_SUN static
144#else
145#define LABEL_IS_SUN 0
146#define STATIC_SUN extern
147#endif
148
149#if ENABLE_FEATURE_SGI_LABEL
150#define LABEL_IS_SGI (label_sgi == current_label_type)
151#define STATIC_SGI static
152#else
153#define LABEL_IS_SGI 0
154#define STATIC_SGI extern
155#endif
156
157#if ENABLE_FEATURE_AIX_LABEL
158#define LABEL_IS_AIX (label_aix == current_label_type)
159#define STATIC_AIX static
160#else
161#define LABEL_IS_AIX 0
162#define STATIC_AIX extern
163#endif
164
165#if ENABLE_FEATURE_OSF_LABEL
166#define LABEL_IS_OSF (label_osf == current_label_type)
167#define STATIC_OSF static
168#else
169#define LABEL_IS_OSF 0
170#define STATIC_OSF extern
171#endif
172
173enum action { fdisk, require, try_only, create_empty_dos, create_empty_sun };
174
175static enum label_type current_label_type;
176
177static const char *disk_device;
178static int fd; /* the disk */
179static int partitions = 4; /* maximum partition + 1 */
180static int display_in_cyl_units = 1;
181static unsigned units_per_sector = 1;
182#if ENABLE_FEATURE_FDISK_WRITABLE
183static void change_units(void);
184static void reread_partition_table(int leave);
185static void delete_partition(int i);
186static int get_partition(int warn, int max);
187static void list_types(const struct systypes *sys);
188static unsigned read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, char *mesg);
189#endif
190static const char *partition_type(unsigned char type);
191static void fdisk_fatal(enum failure why) ATTRIBUTE_NORETURN;
192static void get_geometry(void);
193static int get_boot(enum action what);
194
195#define PLURAL 0
196#define SINGULAR 1
197
198#define hex_val(c) ({ \
199 char _c = (c); \
200 isdigit(_c) ? _c - '0' : \
201 tolower(_c) + 10 - 'a'; \
202 })
203
204
205#define LINE_LENGTH 800
206#define pt_offset(b, n) ((struct partition *)((b) + 0x1be + \
207 (n) * sizeof(struct partition)))
208#define sector(s) ((s) & 0x3f)
209#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2))
210
211#define hsc2sector(h,s,c) (sector(s) - 1 + sectors * \
212 ((h) + heads * cylinder(s,c)))
213#define set_hsc(h,s,c,sector) { \
214 s = sector % sectors + 1; \
215 sector /= sectors; \
216 h = sector % heads; \
217 sector /= heads; \
218 c = sector & 0xff; \
219 s |= (sector >> 2) & 0xc0; \
220 }
221
222
223static int32_t get_start_sect(const struct partition *p);
224static int32_t get_nr_sects(const struct partition *p);
225
226/*
227 * per partition table entry data
228 *
229 * The four primary partitions have the same sectorbuffer (MBRbuffer)
230 * and have NULL ext_pointer.
231 * Each logical partition table entry has two pointers, one for the
232 * partition and one link to the next one.
233 */
234static struct pte {
235 struct partition *part_table; /* points into sectorbuffer */
236 struct partition *ext_pointer; /* points into sectorbuffer */
237#if ENABLE_FEATURE_FDISK_WRITABLE
238 char changed; /* boolean */
239#endif
240 off_t offset; /* disk sector number */
241 char *sectorbuffer; /* disk sector contents */
242} ptes[MAXIMUM_PARTS];
243
244
245#if ENABLE_FEATURE_FDISK_WRITABLE
246static void
247set_all_unchanged(void)
248{
249 int i;
250
251 for (i = 0; i < MAXIMUM_PARTS; i++)
252 ptes[i].changed = 0;
253}
254
255extern inline void
256set_changed(int i)
257{
258 ptes[i].changed = 1;
259}
260#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
261
262extern inline struct partition *
263get_part_table(int i)
264{
265 return ptes[i].part_table;
266}
267
268static const char *
269str_units(int n)
270{ /* n==1: use singular */
271 if (n == 1)
272 return display_in_cyl_units ? _("cylinder") : _("sector");
273 else
274 return display_in_cyl_units ? _("cylinders") : _("sectors");
275}
276
277static int
278valid_part_table_flag(const char *mbuffer)
279{
280 return (mbuffer[510] == 0x55 && (uint8_t)mbuffer[511] == 0xaa);
281}
282
283#if ENABLE_FEATURE_FDISK_WRITABLE
284extern inline void
285write_part_table_flag(char *b)
286{
287 b[510] = 0x55;
288 b[511] = 0xaa;
289}
290
291static char line_buffer[LINE_LENGTH];
292static char *line_ptr;
293
294/* read line; return 0 or first char */
295static int
296read_line(void)
297{
298 fflush(stdout); /* requested by niles@scyld.com */
299 line_ptr = line_buffer;
300 if (!fgets(line_buffer, LINE_LENGTH, stdin)) {
301 /* error or eof */
302 bb_error_msg_and_die("\ngot EOF, exiting");
303 }
304 while (*line_ptr && !isgraph(*line_ptr))
305 line_ptr++;
306 return *line_ptr;
307}
308
309static char
310read_nonempty(const char *mesg)
311{
312 do {
313 fputs(mesg, stdout);
314 } while (!read_line());
315 return *line_ptr;
316}
317
318static char
319read_maybe_empty(const char *mesg)
320{
321 fputs(mesg, stdout);
322 if (!read_line()) {
323 line_ptr = line_buffer;
324 *line_ptr = '\n';
325 line_ptr[1] = 0;
326 }
327 return *line_ptr;
328}
329
330static int
331read_hex(const struct systypes *sys)
332{
333 unsigned long v;
334 while (1) {
335 read_nonempty(_("Hex code (type L to list codes): "));
336 if (*line_ptr == 'l' || *line_ptr == 'L') {
337 list_types(sys);
338 continue;
339 }
340 v = bb_strtoul(line_ptr, NULL, 16);
341 if (errno || v > 0xff) continue;
342 return v;
343 }
344}
345#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
346
347#include "fdisk_aix.c"
348
349typedef struct {
350 unsigned char info[128]; /* Informative text string */
351 unsigned char spare0[14];
352 struct sun_info {
353 unsigned char spare1;
354 unsigned char id;
355 unsigned char spare2;
356 unsigned char flags;
357 } infos[8];
358 unsigned char spare1[246]; /* Boot information etc. */
359 unsigned short rspeed; /* Disk rotational speed */
360 unsigned short pcylcount; /* Physical cylinder count */
361 unsigned short sparecyl; /* extra sects per cylinder */
362 unsigned char spare2[4]; /* More magic... */
363 unsigned short ilfact; /* Interleave factor */
364 unsigned short ncyl; /* Data cylinder count */
365 unsigned short nacyl; /* Alt. cylinder count */
366 unsigned short ntrks; /* Tracks per cylinder */
367 unsigned short nsect; /* Sectors per track */
368 unsigned char spare3[4]; /* Even more magic... */
369 struct sun_partinfo {
370 uint32_t start_cylinder;
371 uint32_t num_sectors;
372 } partitions[8];
373 unsigned short magic; /* Magic number */
374 unsigned short csum; /* Label xor'd checksum */
375} sun_partition;
376#define sunlabel ((sun_partition *)MBRbuffer)
377#define SUNOS_SWAP 3
378#define SUN_WHOLE_DISK 5
379STATIC_OSF void bsd_select(void);
380STATIC_OSF void xbsd_print_disklabel(int);
381#include "fdisk_osf.c"
382
383#define SGI_VOLHDR 0x00
384/* 1 and 2 were used for drive types no longer supported by SGI */
385#define SGI_SWAP 0x03
386/* 4 and 5 were for filesystem types SGI haven't ever supported on MIPS CPUs */
387#define SGI_VOLUME 0x06
388#define SGI_EFS 0x07
389#define SGI_LVOL 0x08
390#define SGI_RLVOL 0x09
391#define SGI_XFS 0x0a
392#define SGI_XFSLOG 0x0b
393#define SGI_XLV 0x0c
394#define SGI_XVM 0x0d
395#define SGI_ENTIRE_DISK SGI_VOLUME
396#if defined(CONFIG_FEATURE_SGI_LABEL) || defined(CONFIG_FEATURE_SUN_LABEL)
397static uint16_t
398__swap16(uint16_t x)
399{
400 return (x << 8) | (x >> 8);
401}
402
403static uint32_t
404__swap32(uint32_t x)
405{
406 return (x << 24) |
407 ((x & 0xFF00) << 8) |
408 ((x & 0xFF0000) >> 8) |
409 (x >> 24);
410}
411#endif
412
413STATIC_SGI const struct systypes sgi_sys_types[];
414STATIC_SGI unsigned sgi_get_num_sectors(int i);
415STATIC_SGI int sgi_get_sysid(int i);
416STATIC_SGI void sgi_delete_partition(int i);
417STATIC_SGI void sgi_change_sysid(int i, int sys);
418STATIC_SGI void sgi_list_table(int xtra);
419STATIC_SGI void sgi_set_xcyl(void);
420STATIC_SGI int verify_sgi(int verbose);
421STATIC_SGI void sgi_add_partition(int n, int sys);
422STATIC_SGI void sgi_set_swappartition(int i);
423STATIC_SGI const char *sgi_get_bootfile(void);
424STATIC_SGI void sgi_set_bootfile(const char* aFile);
425STATIC_SGI void create_sgiinfo(void);
426STATIC_SGI void sgi_write_table(void);
427STATIC_SGI void sgi_set_bootpartition(int i);
428
429#include "fdisk_sgi.c"
430
431STATIC_SUN const struct systypes sun_sys_types[];
432STATIC_SUN void sun_delete_partition(int i);
433STATIC_SUN void sun_change_sysid(int i, int sys);
434STATIC_SUN void sun_list_table(int xtra);
435STATIC_SUN void sun_set_xcyl(void);
436STATIC_SUN void add_sun_partition(int n, int sys);
437STATIC_SUN void sun_set_alt_cyl(void);
438STATIC_SUN void sun_set_ncyl(int cyl);
439STATIC_SUN void sun_set_xcyl(void);
440STATIC_SUN void sun_set_ilfact(void);
441STATIC_SUN void sun_set_rspeed(void);
442STATIC_SUN void sun_set_pcylcount(void);
443STATIC_SUN void toggle_sunflags(int i, unsigned char mask);
444STATIC_SUN void verify_sun(void);
445STATIC_SUN void sun_write_table(void);
446#include "fdisk_sun.c"
447
448/* DOS partition types */
449
450static const struct systypes i386_sys_types[] = {
451 { "\x00" "Empty" },
452 { "\x01" "FAT12" },
453 { "\x04" "FAT16 <32M" },
454 { "\x05" "Extended" }, /* DOS 3.3+ extended partition */
455 { "\x06" "FAT16" }, /* DOS 16-bit >=32M */
456 { "\x07" "HPFS/NTFS" }, /* OS/2 IFS, eg, HPFS or NTFS or QNX */
457 { "\x0a" "OS/2 Boot Manager" },/* OS/2 Boot Manager */
458 { "\x0b" "Win95 FAT32" },
459 { "\x0c" "Win95 FAT32 (LBA)" },/* LBA really is 'Extended Int 13h' */
460 { "\x0e" "Win95 FAT16 (LBA)" },
461 { "\x0f" "Win95 Ext'd (LBA)" },
462 { "\x11" "Hidden FAT12" },
463 { "\x12" "Compaq diagnostics" },
464 { "\x14" "Hidden FAT16 <32M" },
465 { "\x16" "Hidden FAT16" },
466 { "\x17" "Hidden HPFS/NTFS" },
467 { "\x1b" "Hidden Win95 FAT32" },
468 { "\x1c" "Hidden Win95 FAT32 (LBA)" },
469 { "\x1e" "Hidden Win95 FAT16 (LBA)" },
470 { "\x3c" "PartitionMagic recovery" },
471 { "\x41" "PPC PReP Boot" },
472 { "\x42" "SFS" },
473 { "\x63" "GNU HURD or SysV" }, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */
474 { "\x80" "Old Minix" }, /* Minix 1.4a and earlier */
475 { "\x81" "Minix / old Linux" },/* Minix 1.4b and later */
476 { "\x82" "Linux swap" }, /* also Solaris */
477 { "\x83" "Linux" },
478 { "\x84" "OS/2 hidden C: drive" },
479 { "\x85" "Linux extended" },
480 { "\x86" "NTFS volume set" },
481 { "\x87" "NTFS volume set" },
482 { "\x8e" "Linux LVM" },
483 { "\x9f" "BSD/OS" }, /* BSDI */
484 { "\xa0" "IBM Thinkpad hibernation" },
485 { "\xa5" "FreeBSD" }, /* various BSD flavours */
486 { "\xa6" "OpenBSD" },
487 { "\xa8" "Darwin UFS" },
488 { "\xa9" "NetBSD" },
489 { "\xab" "Darwin boot" },
490 { "\xb7" "BSDI fs" },
491 { "\xb8" "BSDI swap" },
492 { "\xbe" "Solaris boot" },
493 { "\xeb" "BeOS fs" },
494 { "\xee" "EFI GPT" }, /* Intel EFI GUID Partition Table */
495 { "\xef" "EFI (FAT-12/16/32)" },/* Intel EFI System Partition */
496 { "\xf0" "Linux/PA-RISC boot" },/* Linux/PA-RISC boot loader */
497 { "\xf2" "DOS secondary" }, /* DOS 3.3+ secondary */
498 { "\xfd" "Linux raid autodetect" },/* New (2.2.x) raid partition with
499 autodetect using persistent
500 superblock */
501#if 0 /* ENABLE_WEIRD_PARTITION_TYPES */
502 { "\x02" "XENIX root" },
503 { "\x03" "XENIX usr" },
504 { "\x08" "AIX" }, /* AIX boot (AIX -- PS/2 port) or SplitDrive */
505 { "\x09" "AIX bootable" }, /* AIX data or Coherent */
506 { "\x10" "OPUS" },
507 { "\x18" "AST SmartSleep" },
508 { "\x24" "NEC DOS" },
509 { "\x39" "Plan 9" },
510 { "\x40" "Venix 80286" },
511 { "\x4d" "QNX4.x" },
512 { "\x4e" "QNX4.x 2nd part" },
513 { "\x4f" "QNX4.x 3rd part" },
514 { "\x50" "OnTrack DM" },
515 { "\x51" "OnTrack DM6 Aux1" }, /* (or Novell) */
516 { "\x52" "CP/M" }, /* CP/M or Microport SysV/AT */
517 { "\x53" "OnTrack DM6 Aux3" },
518 { "\x54" "OnTrackDM6" },
519 { "\x55" "EZ-Drive" },
520 { "\x56" "Golden Bow" },
521 { "\x5c" "Priam Edisk" },
522 { "\x61" "SpeedStor" },
523 { "\x64" "Novell Netware 286" },
524 { "\x65" "Novell Netware 386" },
525 { "\x70" "DiskSecure Multi-Boot" },
526 { "\x75" "PC/IX" },
527 { "\x93" "Amoeba" },
528 { "\x94" "Amoeba BBT" }, /* (bad block table) */
529 { "\xa7" "NeXTSTEP" },
530 { "\xbb" "Boot Wizard hidden" },
531 { "\xc1" "DRDOS/sec (FAT-12)" },
532 { "\xc4" "DRDOS/sec (FAT-16 < 32M)" },
533 { "\xc6" "DRDOS/sec (FAT-16)" },
534 { "\xc7" "Syrinx" },
535 { "\xda" "Non-FS data" },
536 { "\xdb" "CP/M / CTOS / ..." },/* CP/M or Concurrent CP/M or
537 Concurrent DOS or CTOS */
538 { "\xde" "Dell Utility" }, /* Dell PowerEdge Server utilities */
539 { "\xdf" "BootIt" }, /* BootIt EMBRM */
540 { "\xe1" "DOS access" }, /* DOS access or SpeedStor 12-bit FAT
541 extended partition */
542 { "\xe3" "DOS R/O" }, /* DOS R/O or SpeedStor */
543 { "\xe4" "SpeedStor" }, /* SpeedStor 16-bit FAT extended
544 partition < 1024 cyl. */
545 { "\xf1" "SpeedStor" },
546 { "\xf4" "SpeedStor" }, /* SpeedStor large partition */
547 { "\xfe" "LANstep" }, /* SpeedStor >1024 cyl. or LANstep */
548 { "\xff" "BBT" }, /* Xenix Bad Block Table */
549#endif
550 { 0 }
551};
552
553
554#if ENABLE_FEATURE_FDISK_WRITABLE
555/* start_sect and nr_sects are stored little endian on all machines */
556/* moreover, they are not aligned correctly */
557static void
558store4_little_endian(unsigned char *cp, unsigned val)
559{
560 cp[0] = val;
561 cp[1] = val >> 8;
562 cp[2] = val >> 16;
563 cp[3] = val >> 24;
564}
565#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
566
567static unsigned
568read4_little_endian(const unsigned char *cp)
569{
570 return cp[0] + (cp[1] << 8) + (cp[2] << 16) + (cp[3] << 24);
571}
572
573#if ENABLE_FEATURE_FDISK_WRITABLE
574static void
575set_start_sect(struct partition *p, unsigned start_sect)
576{
577 store4_little_endian(p->start4, start_sect);
578}
579#endif
580
581static int32_t
582get_start_sect(const struct partition *p)
583{
584 return read4_little_endian(p->start4);
585}
586
587#if ENABLE_FEATURE_FDISK_WRITABLE
588static void
589set_nr_sects(struct partition *p, int32_t nr_sects)
590{
591 store4_little_endian(p->size4, nr_sects);
592}
593#endif
594
595static int32_t
596get_nr_sects(const struct partition *p)
597{
598 return read4_little_endian(p->size4);
599}
600
601/* normally O_RDWR, -l option gives O_RDONLY */
602static int type_open = O_RDWR;
603
604
605static int ext_index; /* the prime extended partition */
606static int listing; /* no aborts for fdisk -l */
607static int dos_compatible_flag = ~0;
608#if ENABLE_FEATURE_FDISK_WRITABLE
609static int dos_changed;
610static int nowarn; /* no warnings for fdisk -l/-s */
611#endif
612
613
614
615static unsigned user_cylinders, user_heads, user_sectors;
616static unsigned pt_heads, pt_sectors;
617static unsigned kern_heads, kern_sectors;
618
619static off_t extended_offset; /* offset of link pointers */
620
621static unsigned long long total_number_of_sectors;
622
623
624static jmp_buf listingbuf;
625
626static void fdisk_fatal(enum failure why)
627{
628 const char *message;
629
630 if (listing) {
631 close(fd);
632 longjmp(listingbuf, 1);
633 }
634
635 switch (why) {
636 case unable_to_open:
637 message = "\nUnable to open %s";
638 break;
639 case unable_to_read:
640 message = "\nUnable to read %s";
641 break;
642 case unable_to_seek:
643 message = "\nUnable to seek on %s";
644 break;
645 case unable_to_write:
646 message = "\nUnable to write %s";
647 break;
648 case ioctl_error:
649 message = "\nBLKGETSIZE ioctl failed on %s";
650 break;
651 default:
652 message = "\nFatal error";
653 }
654
655 bb_error_msg_and_die(message, disk_device);
656}
657
658static void
659seek_sector(off_t secno)
660{
661 off_t offset = secno * sector_size;
662 if (lseek(fd, offset, SEEK_SET) == (off_t) -1)
663 fdisk_fatal(unable_to_seek);
664}
665
666#if ENABLE_FEATURE_FDISK_WRITABLE
667static void
668write_sector(off_t secno, char *buf)
669{
670 seek_sector(secno);
671 if (write(fd, buf, sector_size) != sector_size)
672 fdisk_fatal(unable_to_write);
673}
674#endif
675
676/* Allocate a buffer and read a partition table sector */
677static void
678read_pte(struct pte *pe, off_t offset)
679{
680 pe->offset = offset;
681 pe->sectorbuffer = (char *) xmalloc(sector_size);
682 seek_sector(offset);
683 if (read(fd, pe->sectorbuffer, sector_size) != sector_size)
684 fdisk_fatal(unable_to_read);
685#if ENABLE_FEATURE_FDISK_WRITABLE
686 pe->changed = 0;
687#endif
688 pe->part_table = pe->ext_pointer = NULL;
689}
690
691static unsigned
692get_partition_start(const struct pte *pe)
693{
694 return pe->offset + get_start_sect(pe->part_table);
695}
696
697#if ENABLE_FEATURE_FDISK_WRITABLE
698/*
699 * Avoid warning about DOS partitions when no DOS partition was changed.
700 * Here a heuristic "is probably dos partition".
701 * We might also do the opposite and warn in all cases except
702 * for "is probably nondos partition".
703 */
704static int
705is_dos_partition(int t)
706{
707 return (t == 1 || t == 4 || t == 6 ||
708 t == 0x0b || t == 0x0c || t == 0x0e ||
709 t == 0x11 || t == 0x12 || t == 0x14 || t == 0x16 ||
710 t == 0x1b || t == 0x1c || t == 0x1e || t == 0x24 ||
711 t == 0xc1 || t == 0xc4 || t == 0xc6);
712}
713
714static void
715menu(void)
716{
717 if (LABEL_IS_SUN) {
718 puts(_("Command action"));
719 puts(_("\ta\ttoggle a read only flag")); /* sun */
720 puts(_("\tb\tedit bsd disklabel"));
721 puts(_("\tc\ttoggle the mountable flag")); /* sun */
722 puts(_("\td\tdelete a partition"));
723 puts(_("\tl\tlist known partition types"));
724 puts(_("\tm\tprint this menu"));
725 puts(_("\tn\tadd a new partition"));
726 puts(_("\to\tcreate a new empty DOS partition table"));
727 puts(_("\tp\tprint the partition table"));
728 puts(_("\tq\tquit without saving changes"));
729 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
730 puts(_("\tt\tchange a partition's system id"));
731 puts(_("\tu\tchange display/entry units"));
732 puts(_("\tv\tverify the partition table"));
733 puts(_("\tw\twrite table to disk and exit"));
734#if ENABLE_FEATURE_FDISK_ADVANCED
735 puts(_("\tx\textra functionality (experts only)"));
736#endif
737 } else
738 if (LABEL_IS_SGI) {
739 puts(_("Command action"));
740 puts(_("\ta\tselect bootable partition")); /* sgi flavour */
741 puts(_("\tb\tedit bootfile entry")); /* sgi */
742 puts(_("\tc\tselect sgi swap partition")); /* sgi flavour */
743 puts(_("\td\tdelete a partition"));
744 puts(_("\tl\tlist known partition types"));
745 puts(_("\tm\tprint this menu"));
746 puts(_("\tn\tadd a new partition"));
747 puts(_("\to\tcreate a new empty DOS partition table"));
748 puts(_("\tp\tprint the partition table"));
749 puts(_("\tq\tquit without saving changes"));
750 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
751 puts(_("\tt\tchange a partition's system id"));
752 puts(_("\tu\tchange display/entry units"));
753 puts(_("\tv\tverify the partition table"));
754 puts(_("\tw\twrite table to disk and exit"));
755 } else
756 if (LABEL_IS_AIX) {
757 puts(_("Command action"));
758 puts(_("\tm\tprint this menu"));
759 puts(_("\to\tcreate a new empty DOS partition table"));
760 puts(_("\tq\tquit without saving changes"));
761 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
762 } else
763 {
764 puts(_("Command action"));
765 puts(_("\ta\ttoggle a bootable flag"));
766 puts(_("\tb\tedit bsd disklabel"));
767 puts(_("\tc\ttoggle the dos compatibility flag"));
768 puts(_("\td\tdelete a partition"));
769 puts(_("\tl\tlist known partition types"));
770 puts(_("\tm\tprint this menu"));
771 puts(_("\tn\tadd a new partition"));
772 puts(_("\to\tcreate a new empty DOS partition table"));
773 puts(_("\tp\tprint the partition table"));
774 puts(_("\tq\tquit without saving changes"));
775 puts(_("\ts\tcreate a new empty Sun disklabel")); /* sun */
776 puts(_("\tt\tchange a partition's system id"));
777 puts(_("\tu\tchange display/entry units"));
778 puts(_("\tv\tverify the partition table"));
779 puts(_("\tw\twrite table to disk and exit"));
780#if ENABLE_FEATURE_FDISK_ADVANCED
781 puts(_("\tx\textra functionality (experts only)"));
782#endif
783 }
784}
785#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
786
787
788#if ENABLE_FEATURE_FDISK_ADVANCED
789static void
790xmenu(void)
791{
792 if (LABEL_IS_SUN) {
793 puts(_("Command action"));
794 puts(_("\ta\tchange number of alternate cylinders")); /*sun*/
795 puts(_("\tc\tchange number of cylinders"));
796 puts(_("\td\tprint the raw data in the partition table"));
797 puts(_("\te\tchange number of extra sectors per cylinder"));/*sun*/
798 puts(_("\th\tchange number of heads"));
799 puts(_("\ti\tchange interleave factor")); /*sun*/
800 puts(_("\to\tchange rotation speed (rpm)")); /*sun*/
801 puts(_("\tm\tprint this menu"));
802 puts(_("\tp\tprint the partition table"));
803 puts(_("\tq\tquit without saving changes"));
804 puts(_("\tr\treturn to main menu"));
805 puts(_("\ts\tchange number of sectors/track"));
806 puts(_("\tv\tverify the partition table"));
807 puts(_("\tw\twrite table to disk and exit"));
808 puts(_("\ty\tchange number of physical cylinders")); /*sun*/
809 } else
810 if (LABEL_IS_SGI) {
811 puts(_("Command action"));
812 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
813 puts(_("\tc\tchange number of cylinders"));
814 puts(_("\td\tprint the raw data in the partition table"));
815 puts(_("\te\tlist extended partitions")); /* !sun */
816 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
817 puts(_("\th\tchange number of heads"));
818 puts(_("\tm\tprint this menu"));
819 puts(_("\tp\tprint the partition table"));
820 puts(_("\tq\tquit without saving changes"));
821 puts(_("\tr\treturn to main menu"));
822 puts(_("\ts\tchange number of sectors/track"));
823 puts(_("\tv\tverify the partition table"));
824 puts(_("\tw\twrite table to disk and exit"));
825 } else
826 if (LABEL_IS_AIX) {
827 puts(_("Command action"));
828 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
829 puts(_("\tc\tchange number of cylinders"));
830 puts(_("\td\tprint the raw data in the partition table"));
831 puts(_("\te\tlist extended partitions")); /* !sun */
832 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
833 puts(_("\th\tchange number of heads"));
834 puts(_("\tm\tprint this menu"));
835 puts(_("\tp\tprint the partition table"));
836 puts(_("\tq\tquit without saving changes"));
837 puts(_("\tr\treturn to main menu"));
838 puts(_("\ts\tchange number of sectors/track"));
839 puts(_("\tv\tverify the partition table"));
840 puts(_("\tw\twrite table to disk and exit"));
841 } else {
842 puts(_("Command action"));
843 puts(_("\tb\tmove beginning of data in a partition")); /* !sun */
844 puts(_("\tc\tchange number of cylinders"));
845 puts(_("\td\tprint the raw data in the partition table"));
846 puts(_("\te\tlist extended partitions")); /* !sun */
847 puts(_("\tf\tfix partition order")); /* !sun, !aix, !sgi */
848#if ENABLE_FEATURE_SGI_LABEL
849 puts(_("\tg\tcreate an IRIX (SGI) partition table"));/* sgi */
850#endif
851 puts(_("\th\tchange number of heads"));
852 puts(_("\tm\tprint this menu"));
853 puts(_("\tp\tprint the partition table"));
854 puts(_("\tq\tquit without saving changes"));
855 puts(_("\tr\treturn to main menu"));
856 puts(_("\ts\tchange number of sectors/track"));
857 puts(_("\tv\tverify the partition table"));
858 puts(_("\tw\twrite table to disk and exit"));
859 }
860}
861#endif /* ADVANCED mode */
862
863#if ENABLE_FEATURE_FDISK_WRITABLE
864static const struct systypes *
865get_sys_types(void)
866{
867 return (
868 LABEL_IS_SUN ? sun_sys_types :
869 LABEL_IS_SGI ? sgi_sys_types :
870 i386_sys_types);
871}
872#else
873#define get_sys_types() i386_sys_types
874#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
875
876static const char *partition_type(unsigned char type)
877{
878 int i;
879 const struct systypes *types = get_sys_types();
880
881 for (i = 0; types[i].name; i++)
882 if ((unsigned char )types[i].name[0] == type)
883 return types[i].name + 1;
884
885 return _("Unknown");
886}
887
888
889#if ENABLE_FEATURE_FDISK_WRITABLE
890static int
891get_sysid(int i)
892{
893 return LABEL_IS_SUN ? sunlabel->infos[i].id :
894 (LABEL_IS_SGI ? sgi_get_sysid(i) :
895 ptes[i].part_table->sys_ind);
896}
897
898void list_types(const struct systypes *sys)
899{
900 unsigned last[4], done = 0, next = 0, size;
901 int i;
902
903 for (i = 0; sys[i].name; i++);
904 size = i;
905
906 for (i = 3; i >= 0; i--)
907 last[3 - i] = done += (size + i - done) / (i + 1);
908 i = done = 0;
909
910 do {
911 printf("%c%2x %-15.15s", i ? ' ' : '\n',
912 (unsigned char)sys[next].name[0],
913 partition_type((unsigned char)sys[next].name[0]));
914 next = last[i++] + done;
915 if (i > 3 || next >= last[i]) {
916 i = 0;
917 next = ++done;
918 }
919 } while (done < last[0]);
920 putchar('\n');
921}
922#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
923
924static int
925is_cleared_partition(const struct partition *p)
926{
927 return !(!p || p->boot_ind || p->head || p->sector || p->cyl ||
928 p->sys_ind || p->end_head || p->end_sector || p->end_cyl ||
929 get_start_sect(p) || get_nr_sects(p));
930}
931
932static void
933clear_partition(struct partition *p)
934{
935 if (!p)
936 return;
937 memset(p, 0, sizeof(struct partition));
938}
939
940#if ENABLE_FEATURE_FDISK_WRITABLE
941static void
942set_partition(int i, int doext, off_t start, off_t stop, int sysid)
943{
944 struct partition *p;
945 off_t offset;
946
947 if (doext) {
948 p = ptes[i].ext_pointer;
949 offset = extended_offset;
950 } else {
951 p = ptes[i].part_table;
952 offset = ptes[i].offset;
953 }
954 p->boot_ind = 0;
955 p->sys_ind = sysid;
956 set_start_sect(p, start - offset);
957 set_nr_sects(p, stop - start + 1);
958 if (dos_compatible_flag && (start/(sectors*heads) > 1023))
959 start = heads*sectors*1024 - 1;
960 set_hsc(p->head, p->sector, p->cyl, start);
961 if (dos_compatible_flag && (stop/(sectors*heads) > 1023))
962 stop = heads*sectors*1024 - 1;
963 set_hsc(p->end_head, p->end_sector, p->end_cyl, stop);
964 ptes[i].changed = 1;
965}
966#endif
967
968static int
969test_c(const char **m, const char *mesg)
970{
971 int val = 0;
972 if (!*m)
973 printf(_("You must set"));
974 else {
975 printf(" %s", *m);
976 val = 1;
977 }
978 *m = mesg;
979 return val;
980}
981
982static int
983warn_geometry(void)
984{
985 const char *m = NULL;
986 int prev = 0;
987
988 if (!heads)
989 prev = test_c(&m, _("heads"));
990 if (!sectors)
991 prev = test_c(&m, _("sectors"));
992 if (!cylinders)
993 prev = test_c(&m, _("cylinders"));
994 if (!m)
995 return 0;
996
997 printf("%s%s.\n"
998#if ENABLE_FEATURE_FDISK_WRITABLE
999 "You can do this from the extra functions menu.\n"
1000#endif
1001 , prev ? _(" and ") : " ", m);
1002
1003 return 1;
1004}
1005
1006static void update_units(void)
1007{
1008 int cyl_units = heads * sectors;
1009
1010 if (display_in_cyl_units && cyl_units)
1011 units_per_sector = cyl_units;
1012 else
1013 units_per_sector = 1; /* in sectors */
1014}
1015
1016#if ENABLE_FEATURE_FDISK_WRITABLE
1017static void
1018warn_cylinders(void)
1019{
1020 if (LABEL_IS_DOS && cylinders > 1024 && !nowarn)
1021 printf(_("\n"
1022"The number of cylinders for this disk is set to %d.\n"
1023"There is nothing wrong with that, but this is larger than 1024,\n"
1024"and could in certain setups cause problems with:\n"
1025"1) software that runs at boot time (e.g., old versions of LILO)\n"
1026"2) booting and partitioning software from other OSs\n"
1027" (e.g., DOS FDISK, OS/2 FDISK)\n"),
1028 cylinders);
1029}
1030#endif
1031
1032static void
1033read_extended(int ext)
1034{
1035 int i;
1036 struct pte *pex;
1037 struct partition *p, *q;
1038
1039 ext_index = ext;
1040 pex = &ptes[ext];
1041 pex->ext_pointer = pex->part_table;
1042
1043 p = pex->part_table;
1044 if (!get_start_sect(p)) {
1045 printf(_("Bad offset in primary extended partition\n"));
1046 return;
1047 }
1048
1049 while (IS_EXTENDED(p->sys_ind)) {
1050 struct pte *pe = &ptes[partitions];
1051
1052 if (partitions >= MAXIMUM_PARTS) {
1053 /* This is not a Linux restriction, but
1054 this program uses arrays of size MAXIMUM_PARTS.
1055 Do not try to 'improve' this test. */
1056 struct pte *pre = &ptes[partitions-1];
1057#if ENABLE_FEATURE_FDISK_WRITABLE
1058 printf(_("Warning: deleting partitions after %d\n"),
1059 partitions);
1060 pre->changed = 1;
1061#endif
1062 clear_partition(pre->ext_pointer);
1063 return;
1064 }
1065
1066 read_pte(pe, extended_offset + get_start_sect(p));
1067
1068 if (!extended_offset)
1069 extended_offset = get_start_sect(p);
1070
1071 q = p = pt_offset(pe->sectorbuffer, 0);
1072 for (i = 0; i < 4; i++, p++) if (get_nr_sects(p)) {
1073 if (IS_EXTENDED(p->sys_ind)) {
1074 if (pe->ext_pointer)
1075 printf(_("Warning: extra link "
1076 "pointer in partition table"
1077 " %d\n"), partitions + 1);
1078 else
1079 pe->ext_pointer = p;
1080 } else if (p->sys_ind) {
1081 if (pe->part_table)
1082 printf(_("Warning: ignoring extra "
1083 "data in partition table"
1084 " %d\n"), partitions + 1);
1085 else
1086 pe->part_table = p;
1087 }
1088 }
1089
1090 /* very strange code here... */
1091 if (!pe->part_table) {
1092 if (q != pe->ext_pointer)
1093 pe->part_table = q;
1094 else
1095 pe->part_table = q + 1;
1096 }
1097 if (!pe->ext_pointer) {
1098 if (q != pe->part_table)
1099 pe->ext_pointer = q;
1100 else
1101 pe->ext_pointer = q + 1;
1102 }
1103
1104 p = pe->ext_pointer;
1105 partitions++;
1106 }
1107
1108#if ENABLE_FEATURE_FDISK_WRITABLE
1109 /* remove empty links */
1110 remove:
1111 for (i = 4; i < partitions; i++) {
1112 struct pte *pe = &ptes[i];
1113
1114 if (!get_nr_sects(pe->part_table) &&
1115 (partitions > 5 || ptes[4].part_table->sys_ind)) {
1116 printf("omitting empty partition (%d)\n", i+1);
1117 delete_partition(i);
1118 goto remove; /* numbering changed */
1119 }
1120 }
1121#endif
1122}
1123
1124#if ENABLE_FEATURE_FDISK_WRITABLE
1125static void
1126create_doslabel(void)
1127{
1128 int i;
1129
1130 printf(
1131 _("Building a new DOS disklabel. Changes will remain in memory only,\n"
1132 "until you decide to write them. After that, of course, the previous\n"
1133 "content won't be recoverable.\n\n"));
1134
1135 current_label_type = label_dos;
1136
1137#if ENABLE_FEATURE_OSF_LABEL
1138 possibly_osf_label = 0;
1139#endif
1140 partitions = 4;
1141
1142 for (i = 510-64; i < 510; i++)
1143 MBRbuffer[i] = 0;
1144 write_part_table_flag(MBRbuffer);
1145 extended_offset = 0;
1146 set_all_unchanged();
1147 set_changed(0);
1148 get_boot(create_empty_dos);
1149}
1150#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
1151
1152static void
1153get_sectorsize(void)
1154{
1155 if (!user_set_sector_size) {
1156 int arg;
1157 if (ioctl(fd, BLKSSZGET, &arg) == 0)
1158 sector_size = arg;
1159 if (sector_size != DEFAULT_SECTOR_SIZE)
1160 printf(_("Note: sector size is %d (not %d)\n"),
1161 sector_size, DEFAULT_SECTOR_SIZE);
1162 }
1163}
1164
1165static void
1166get_kernel_geometry(void)
1167{
1168 struct hd_geometry geometry;
1169
1170 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
1171 kern_heads = geometry.heads;
1172 kern_sectors = geometry.sectors;
1173 /* never use geometry.cylinders - it is truncated */
1174 }
1175}
1176
1177static void
1178get_partition_table_geometry(void)
1179{
1180 const unsigned char *bufp = (const unsigned char *)MBRbuffer;
1181 struct partition *p;
1182 int i, h, s, hh, ss;
1183 int first = 1;
1184 int bad = 0;
1185
1186 if (!(valid_part_table_flag((char*)bufp)))
1187 return;
1188
1189 hh = ss = 0;
1190 for (i = 0; i < 4; i++) {
1191 p = pt_offset(bufp, i);
1192 if (p->sys_ind != 0) {
1193 h = p->end_head + 1;
1194 s = (p->end_sector & 077);
1195 if (first) {
1196 hh = h;
1197 ss = s;
1198 first = 0;
1199 } else if (hh != h || ss != s)
1200 bad = 1;
1201 }
1202 }
1203
1204 if (!first && !bad) {
1205 pt_heads = hh;
1206 pt_sectors = ss;
1207 }
1208}
1209
1210static void
1211get_geometry(void)
1212{
1213 int sec_fac;
1214 unsigned long long bytes; /* really u64 */
1215
1216 get_sectorsize();
1217 sec_fac = sector_size / 512;
1218#if ENABLE_FEATURE_SUN_LABEL
1219 guess_device_type();
1220#endif
1221 heads = cylinders = sectors = 0;
1222 kern_heads = kern_sectors = 0;
1223 pt_heads = pt_sectors = 0;
1224
1225 get_kernel_geometry();
1226 get_partition_table_geometry();
1227
1228 heads = user_heads ? user_heads :
1229 pt_heads ? pt_heads :
1230 kern_heads ? kern_heads : 255;
1231 sectors = user_sectors ? user_sectors :
1232 pt_sectors ? pt_sectors :
1233 kern_sectors ? kern_sectors : 63;
1234 if (ioctl(fd, BLKGETSIZE64, &bytes) == 0) {
1235 /* got bytes */
1236 } else {
1237 unsigned long longsectors;
1238
1239 if (ioctl(fd, BLKGETSIZE, &longsectors))
1240 longsectors = 0;
1241 bytes = ((unsigned long long) longsectors) << 9;
1242 }
1243
1244 total_number_of_sectors = (bytes >> 9);
1245
1246 sector_offset = 1;
1247 if (dos_compatible_flag)
1248 sector_offset = sectors;
1249
1250 cylinders = total_number_of_sectors / (heads * sectors * sec_fac);
1251 if (!cylinders)
1252 cylinders = user_cylinders;
1253}
1254
1255/*
1256 * Read MBR. Returns:
1257 * -1: no 0xaa55 flag present (possibly entire disk BSD)
1258 * 0: found or created label
1259 * 1: I/O error
1260 */
1261static int
1262get_boot(enum action what)
1263{
1264 int i;
1265
1266 partitions = 4;
1267
1268 for (i = 0; i < 4; i++) {
1269 struct pte *pe = &ptes[i];
1270
1271 pe->part_table = pt_offset(MBRbuffer, i);
1272 pe->ext_pointer = NULL;
1273 pe->offset = 0;
1274 pe->sectorbuffer = MBRbuffer;
1275#if ENABLE_FEATURE_FDISK_WRITABLE
1276 pe->changed = (what == create_empty_dos);
1277#endif
1278 }
1279
1280#if ENABLE_FEATURE_SUN_LABEL
1281 if (what == create_empty_sun && check_sun_label())
1282 return 0;
1283#endif
1284
1285 memset(MBRbuffer, 0, 512);
1286
1287#if ENABLE_FEATURE_FDISK_WRITABLE
1288 if (what == create_empty_dos)
1289 goto got_dos_table; /* skip reading disk */
1290
1291 if ((fd = open(disk_device, type_open)) < 0) {
1292 if ((fd = open(disk_device, O_RDONLY)) < 0) {
1293 if (what == try_only)
1294 return 1;
1295 fdisk_fatal(unable_to_open);
1296 } else
1297 printf(_("You will not be able to write "
1298 "the partition table.\n"));
1299 }
1300
1301 if (512 != read(fd, MBRbuffer, 512)) {
1302 if (what == try_only)
1303 return 1;
1304 fdisk_fatal(unable_to_read);
1305 }
1306#else
1307 if ((fd = open(disk_device, O_RDONLY)) < 0)
1308 return 1;
1309 if (512 != read(fd, MBRbuffer, 512))
1310 return 1;
1311#endif
1312
1313 get_geometry();
1314
1315 update_units();
1316
1317#if ENABLE_FEATURE_SUN_LABEL
1318 if (check_sun_label())
1319 return 0;
1320#endif
1321
1322#if ENABLE_FEATURE_SGI_LABEL
1323 if (check_sgi_label())
1324 return 0;
1325#endif
1326
1327#if ENABLE_FEATURE_AIX_LABEL
1328 if (check_aix_label())
1329 return 0;
1330#endif
1331
1332#if ENABLE_FEATURE_OSF_LABEL
1333 if (check_osf_label()) {
1334 possibly_osf_label = 1;
1335 if (!valid_part_table_flag(MBRbuffer)) {
1336 current_label_type = label_osf;
1337 return 0;
1338 }
1339 printf(_("This disk has both DOS and BSD magic.\n"
1340 "Give the 'b' command to go to BSD mode.\n"));
1341 }
1342#endif
1343
1344#if ENABLE_FEATURE_FDISK_WRITABLE
1345 got_dos_table:
1346#endif
1347
1348 if (!valid_part_table_flag(MBRbuffer)) {
1349#ifndef CONFIG_FEATURE_FDISK_WRITABLE
1350 return -1;
1351#else
1352 switch (what) {
1353 case fdisk:
1354 printf(_("Device contains neither a valid DOS "
1355 "partition table, nor Sun, SGI or OSF "
1356 "disklabel\n"));
1357#ifdef __sparc__
1358#if ENABLE_FEATURE_SUN_LABEL
1359 create_sunlabel();
1360#endif
1361#else
1362 create_doslabel();
1363#endif
1364 return 0;
1365 case try_only:
1366 return -1;
1367 case create_empty_dos:
1368#if ENABLE_FEATURE_SUN_LABEL
1369 case create_empty_sun:
1370#endif
1371 break;
1372 default:
1373 bb_error_msg_and_die(_("internal error"));
1374 }
1375#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
1376 }
1377
1378#if ENABLE_FEATURE_FDISK_WRITABLE
1379 warn_cylinders();
1380#endif
1381 warn_geometry();
1382
1383 for (i = 0; i < 4; i++) {
1384 struct pte *pe = &ptes[i];
1385
1386 if (IS_EXTENDED(pe->part_table->sys_ind)) {
1387 if (partitions != 4)
1388 printf(_("Ignoring extra extended "
1389 "partition %d\n"), i + 1);
1390 else
1391 read_extended(i);
1392 }
1393 }
1394
1395 for (i = 3; i < partitions; i++) {
1396 struct pte *pe = &ptes[i];
1397
1398 if (!valid_part_table_flag(pe->sectorbuffer)) {
1399 printf(_("Warning: invalid flag 0x%02x,0x%02x of partition "
1400 "table %d will be corrected by w(rite)\n"),
1401 pe->sectorbuffer[510],
1402 pe->sectorbuffer[511],
1403 i + 1);
1404#if ENABLE_FEATURE_FDISK_WRITABLE
1405 pe->changed = 1;
1406#endif
1407 }
1408 }
1409
1410 return 0;
1411}
1412
1413#if ENABLE_FEATURE_FDISK_WRITABLE
1414/*
1415 * Print the message MESG, then read an integer between LOW and HIGH (inclusive).
1416 * If the user hits Enter, DFLT is returned.
1417 * Answers like +10 are interpreted as offsets from BASE.
1418 *
1419 * There is no default if DFLT is not between LOW and HIGH.
1420 */
1421static unsigned
1422read_int(unsigned low, unsigned dflt, unsigned high, unsigned base, char *mesg)
1423{
1424 unsigned i;
1425 int default_ok = 1;
1426 const char *fmt = "%s (%u-%u, default %u): ";
1427
1428 if (dflt < low || dflt > high) {
1429 fmt = "%s (%u-%u): ";
1430 default_ok = 0;
1431 }
1432
1433 while (1) {
1434 int use_default = default_ok;
1435
1436 /* ask question and read answer */
1437 do {
1438 printf(fmt, mesg, low, high, dflt);
1439 read_maybe_empty("");
1440 } while (*line_ptr != '\n' && !isdigit(*line_ptr)
1441 && *line_ptr != '-' && *line_ptr != '+');
1442
1443 if (*line_ptr == '+' || *line_ptr == '-') {
1444 int minus = (*line_ptr == '-');
1445 int absolute = 0;
1446
1447 i = atoi(line_ptr + 1);
1448
1449 while (isdigit(*++line_ptr))
1450 use_default = 0;
1451
1452 switch (*line_ptr) {
1453 case 'c':
1454 case 'C':
1455 if (!display_in_cyl_units)
1456 i *= heads * sectors;
1457 break;
1458 case 'K':
1459 absolute = 1024;
1460 break;
1461 case 'k':
1462 absolute = 1000;
1463 break;
1464 case 'm':
1465 case 'M':
1466 absolute = 1000000;
1467 break;
1468 case 'g':
1469 case 'G':
1470 absolute = 1000000000;
1471 break;
1472 default:
1473 break;
1474 }
1475 if (absolute) {
1476 unsigned long long bytes;
1477 unsigned long unit;
1478
1479 bytes = (unsigned long long) i * absolute;
1480 unit = sector_size * units_per_sector;
1481 bytes += unit/2; /* round */
1482 bytes /= unit;
1483 i = bytes;
1484 }
1485 if (minus)
1486 i = -i;
1487 i += base;
1488 } else {
1489 i = atoi(line_ptr);
1490 while (isdigit(*line_ptr)) {
1491 line_ptr++;
1492 use_default = 0;
1493 }
1494 }
1495 if (use_default)
1496 printf(_("Using default value %u\n"), i = dflt);
1497 if (i >= low && i <= high)
1498 break;
1499 else
1500 printf(_("Value is out of range\n"));
1501 }
1502 return i;
1503}
1504
1505static int
1506get_partition(int warn, int max)
1507{
1508 struct pte *pe;
1509 int i;
1510
1511 i = read_int(1, 0, max, 0, _("Partition number")) - 1;
1512 pe = &ptes[i];
1513
1514 if (warn) {
1515 if ((!LABEL_IS_SUN && !LABEL_IS_SGI && !pe->part_table->sys_ind)
1516 || (LABEL_IS_SUN && (!sunlabel->partitions[i].num_sectors || !sunlabel->infos[i].id))
1517 || (LABEL_IS_SGI && !sgi_get_num_sectors(i))
1518 ) {
1519 printf(_("Warning: partition %d has empty type\n"), i+1);
1520 }
1521 }
1522 return i;
1523}
1524
1525static int
1526get_existing_partition(int warn, int max)
1527{
1528 int pno = -1;
1529 int i;
1530
1531 for (i = 0; i < max; i++) {
1532 struct pte *pe = &ptes[i];
1533 struct partition *p = pe->part_table;
1534
1535 if (p && !is_cleared_partition(p)) {
1536 if (pno >= 0)
1537 goto not_unique;
1538 pno = i;
1539 }
1540 }
1541 if (pno >= 0) {
1542 printf(_("Selected partition %d\n"), pno+1);
1543 return pno;
1544 }
1545 printf(_("No partition is defined yet!\n"));
1546 return -1;
1547
1548 not_unique:
1549 return get_partition(warn, max);
1550}
1551
1552static int
1553get_nonexisting_partition(int warn, int max)
1554{
1555 int pno = -1;
1556 int i;
1557
1558 for (i = 0; i < max; i++) {
1559 struct pte *pe = &ptes[i];
1560 struct partition *p = pe->part_table;
1561
1562 if (p && is_cleared_partition(p)) {
1563 if (pno >= 0)
1564 goto not_unique;
1565 pno = i;
1566 }
1567 }
1568 if (pno >= 0) {
1569 printf(_("Selected partition %d\n"), pno+1);
1570 return pno;
1571 }
1572 printf(_("All primary partitions have been defined already!\n"));
1573 return -1;
1574
1575 not_unique:
1576 return get_partition(warn, max);
1577}
1578
1579
1580static void
1581change_units(void)
1582{
1583 display_in_cyl_units = !display_in_cyl_units;
1584 update_units();
1585 printf(_("Changing display/entry units to %s\n"),
1586 str_units(PLURAL));
1587}
1588
1589static void
1590toggle_active(int i)
1591{
1592 struct pte *pe = &ptes[i];
1593 struct partition *p = pe->part_table;
1594
1595 if (IS_EXTENDED(p->sys_ind) && !p->boot_ind)
1596 printf(_("WARNING: Partition %d is an extended partition\n"), i + 1);
1597 p->boot_ind = (p->boot_ind ? 0 : ACTIVE_FLAG);
1598 pe->changed = 1;
1599}
1600
1601static void
1602toggle_dos_compatibility_flag(void)
1603{
1604 dos_compatible_flag = ~dos_compatible_flag;
1605 if (dos_compatible_flag) {
1606 sector_offset = sectors;
1607 printf(_("DOS Compatibility flag is set\n"));
1608 }
1609 else {
1610 sector_offset = 1;
1611 printf(_("DOS Compatibility flag is not set\n"));
1612 }
1613}
1614
1615static void
1616delete_partition(int i)
1617{
1618 struct pte *pe = &ptes[i];
1619 struct partition *p = pe->part_table;
1620 struct partition *q = pe->ext_pointer;
1621
1622/* Note that for the fifth partition (i == 4) we don't actually
1623 * decrement partitions.
1624 */
1625
1626 if (warn_geometry())
1627 return; /* C/H/S not set */
1628 pe->changed = 1;
1629
1630 if (LABEL_IS_SUN) {
1631 sun_delete_partition(i);
1632 return;
1633 }
1634 if (LABEL_IS_SGI) {
1635 sgi_delete_partition(i);
1636 return;
1637 }
1638
1639 if (i < 4) {
1640 if (IS_EXTENDED(p->sys_ind) && i == ext_index) {
1641 partitions = 4;
1642 ptes[ext_index].ext_pointer = NULL;
1643 extended_offset = 0;
1644 }
1645 clear_partition(p);
1646 return;
1647 }
1648
1649 if (!q->sys_ind && i > 4) {
1650 /* the last one in the chain - just delete */
1651 --partitions;
1652 --i;
1653 clear_partition(ptes[i].ext_pointer);
1654 ptes[i].changed = 1;
1655 } else {
1656 /* not the last one - further ones will be moved down */
1657 if (i > 4) {
1658 /* delete this link in the chain */
1659 p = ptes[i-1].ext_pointer;
1660 *p = *q;
1661 set_start_sect(p, get_start_sect(q));
1662 set_nr_sects(p, get_nr_sects(q));
1663 ptes[i-1].changed = 1;
1664 } else if (partitions > 5) { /* 5 will be moved to 4 */
1665 /* the first logical in a longer chain */
1666 pe = &ptes[5];
1667
1668 if (pe->part_table) /* prevent SEGFAULT */
1669 set_start_sect(pe->part_table,
1670 get_partition_start(pe) -
1671 extended_offset);
1672 pe->offset = extended_offset;
1673 pe->changed = 1;
1674 }
1675
1676 if (partitions > 5) {
1677 partitions--;
1678 while (i < partitions) {
1679 ptes[i] = ptes[i+1];
1680 i++;
1681 }
1682 } else
1683 /* the only logical: clear only */
1684 clear_partition(ptes[i].part_table);
1685 }
1686}
1687
1688static void
1689change_sysid(void)
1690{
1691 int i, sys, origsys;
1692 struct partition *p;
1693
1694 /* If sgi_label then don't use get_existing_partition,
1695 let the user select a partition, since get_existing_partition()
1696 only works for Linux like partition tables. */
1697 if (!LABEL_IS_SGI) {
1698 i = get_existing_partition(0, partitions);
1699 } else {
1700 i = get_partition(0, partitions);
1701 }
1702 if (i == -1)
1703 return;
1704 p = ptes[i].part_table;
1705 origsys = sys = get_sysid(i);
1706
1707 /* if changing types T to 0 is allowed, then
1708 the reverse change must be allowed, too */
1709 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN && !get_nr_sects(p)) {
1710 printf(_("Partition %d does not exist yet!\n"), i + 1);
1711 return;
1712 }
1713 while (1) {
1714 sys = read_hex (get_sys_types());
1715
1716 if (!sys && !LABEL_IS_SGI && !LABEL_IS_SUN) {
1717 printf(_("Type 0 means free space to many systems\n"
1718 "(but not to Linux). Having partitions of\n"
1719 "type 0 is probably unwise. You can delete\n"
1720 "a partition using the 'd' command.\n"));
1721 /* break; */
1722 }
1723
1724 if (!LABEL_IS_SUN && !LABEL_IS_SGI) {
1725 if (IS_EXTENDED(sys) != IS_EXTENDED(p->sys_ind)) {
1726 printf(_("You cannot change a partition into"
1727 " an extended one or vice versa\n"
1728 "Delete it first.\n"));
1729 break;
1730 }
1731 }
1732
1733 if (sys < 256) {
1734 if (LABEL_IS_SUN && i == 2 && sys != SUN_WHOLE_DISK)
1735 printf(_("Consider leaving partition 3 "
1736 "as Whole disk (5),\n"
1737 "as SunOS/Solaris expects it and "
1738 "even Linux likes it.\n\n"));
1739 if (LABEL_IS_SGI &&
1740 (
1741 (i == 10 && sys != SGI_ENTIRE_DISK) ||
1742 (i == 8 && sys != 0)
1743 )
1744 ){
1745 printf(_("Consider leaving partition 9 "
1746 "as volume header (0),\nand "
1747 "partition 11 as entire volume (6)"
1748 "as IRIX expects it.\n\n"));
1749 }
1750 if (sys == origsys)
1751 break;
1752 if (LABEL_IS_SUN) {
1753 sun_change_sysid(i, sys);
1754 } else if (LABEL_IS_SGI) {
1755 sgi_change_sysid(i, sys);
1756 } else
1757 p->sys_ind = sys;
1758
1759 printf(_("Changed system type of partition %d "
1760 "to %x (%s)\n"), i + 1, sys,
1761 partition_type(sys));
1762 ptes[i].changed = 1;
1763 if (is_dos_partition(origsys) ||
1764 is_dos_partition(sys))
1765 dos_changed = 1;
1766 break;
1767 }
1768 }
1769}
1770#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
1771
1772
1773/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993,
1774 * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross,
1775 * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S.
1776 * Lubkin Oct. 1991). */
1777
1778static void
1779long2chs(ulong ls, unsigned *c, unsigned *h, unsigned *s)
1780{
1781 int spc = heads * sectors;
1782
1783 *c = ls / spc;
1784 ls = ls % spc;
1785 *h = ls / sectors;
1786 *s = ls % sectors + 1; /* sectors count from 1 */
1787}
1788
1789static void
1790check_consistency(const struct partition *p, int partition)
1791{
1792 unsigned pbc, pbh, pbs; /* physical beginning c, h, s */
1793 unsigned pec, peh, pes; /* physical ending c, h, s */
1794 unsigned lbc, lbh, lbs; /* logical beginning c, h, s */
1795 unsigned lec, leh, les; /* logical ending c, h, s */
1796
1797 if (!heads || !sectors || (partition >= 4))
1798 return; /* do not check extended partitions */
1799
1800/* physical beginning c, h, s */
1801 pbc = (p->cyl & 0xff) | ((p->sector << 2) & 0x300);
1802 pbh = p->head;
1803 pbs = p->sector & 0x3f;
1804
1805/* physical ending c, h, s */
1806 pec = (p->end_cyl & 0xff) | ((p->end_sector << 2) & 0x300);
1807 peh = p->end_head;
1808 pes = p->end_sector & 0x3f;
1809
1810/* compute logical beginning (c, h, s) */
1811 long2chs(get_start_sect(p), &lbc, &lbh, &lbs);
1812
1813/* compute logical ending (c, h, s) */
1814 long2chs(get_start_sect(p) + get_nr_sects(p) - 1, &lec, &leh, &les);
1815
1816/* Same physical / logical beginning? */
1817 if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) {
1818 printf(_("Partition %d has different physical/logical "
1819 "beginnings (non-Linux?):\n"), partition + 1);
1820 printf(_(" phys=(%d, %d, %d) "), pbc, pbh, pbs);
1821 printf(_("logical=(%d, %d, %d)\n"),lbc, lbh, lbs);
1822 }
1823
1824/* Same physical / logical ending? */
1825 if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) {
1826 printf(_("Partition %d has different physical/logical "
1827 "endings:\n"), partition + 1);
1828 printf(_(" phys=(%d, %d, %d) "), pec, peh, pes);
1829 printf(_("logical=(%d, %d, %d)\n"),lec, leh, les);
1830 }
1831
1832/* Ending on cylinder boundary? */
1833 if (peh != (heads - 1) || pes != sectors) {
1834 printf(_("Partition %i does not end on cylinder boundary.\n"),
1835 partition + 1);
1836 }
1837}
1838
1839static void
1840list_disk_geometry(void)
1841{
1842 long long bytes = (total_number_of_sectors << 9);
1843 long megabytes = bytes/1000000;
1844
1845 if (megabytes < 10000)
1846 printf(_("\nDisk %s: %ld MB, %lld bytes\n"),
1847 disk_device, megabytes, bytes);
1848 else
1849 printf(_("\nDisk %s: %ld.%ld GB, %lld bytes\n"),
1850 disk_device, megabytes/1000, (megabytes/100)%10, bytes);
1851 printf(_("%d heads, %d sectors/track, %d cylinders"),
1852 heads, sectors, cylinders);
1853 if (units_per_sector == 1)
1854 printf(_(", total %llu sectors"),
1855 total_number_of_sectors / (sector_size/512));
1856 printf(_("\nUnits = %s of %d * %d = %d bytes\n\n"),
1857 str_units(PLURAL),
1858 units_per_sector, sector_size, units_per_sector * sector_size);
1859}
1860
1861/*
1862 * Check whether partition entries are ordered by their starting positions.
1863 * Return 0 if OK. Return i if partition i should have been earlier.
1864 * Two separate checks: primary and logical partitions.
1865 */
1866static int
1867wrong_p_order(int *prev)
1868{
1869 const struct pte *pe;
1870 const struct partition *p;
1871 off_t last_p_start_pos = 0, p_start_pos;
1872 int i, last_i = 0;
1873
1874 for (i = 0 ; i < partitions; i++) {
1875 if (i == 4) {
1876 last_i = 4;
1877 last_p_start_pos = 0;
1878 }
1879 pe = &ptes[i];
1880 if ((p = pe->part_table)->sys_ind) {
1881 p_start_pos = get_partition_start(pe);
1882
1883 if (last_p_start_pos > p_start_pos) {
1884 if (prev)
1885 *prev = last_i;
1886 return i;
1887 }
1888
1889 last_p_start_pos = p_start_pos;
1890 last_i = i;
1891 }
1892 }
1893 return 0;
1894}
1895
1896#if ENABLE_FEATURE_FDISK_ADVANCED
1897/*
1898 * Fix the chain of logicals.
1899 * extended_offset is unchanged, the set of sectors used is unchanged
1900 * The chain is sorted so that sectors increase, and so that
1901 * starting sectors increase.
1902 *
1903 * After this it may still be that cfdisk doesnt like the table.
1904 * (This is because cfdisk considers expanded parts, from link to
1905 * end of partition, and these may still overlap.)
1906 * Now
1907 * sfdisk /dev/hda > ohda; sfdisk /dev/hda < ohda
1908 * may help.
1909 */
1910static void
1911fix_chain_of_logicals(void)
1912{
1913 int j, oj, ojj, sj, sjj;
1914 struct partition *pj,*pjj,tmp;
1915
1916 /* Stage 1: sort sectors but leave sector of part 4 */
1917 /* (Its sector is the global extended_offset.) */
1918 stage1:
1919 for (j = 5; j < partitions-1; j++) {
1920 oj = ptes[j].offset;
1921 ojj = ptes[j+1].offset;
1922 if (oj > ojj) {
1923 ptes[j].offset = ojj;
1924 ptes[j+1].offset = oj;
1925 pj = ptes[j].part_table;
1926 set_start_sect(pj, get_start_sect(pj)+oj-ojj);
1927 pjj = ptes[j+1].part_table;
1928 set_start_sect(pjj, get_start_sect(pjj)+ojj-oj);
1929 set_start_sect(ptes[j-1].ext_pointer,
1930 ojj-extended_offset);
1931 set_start_sect(ptes[j].ext_pointer,
1932 oj-extended_offset);
1933 goto stage1;
1934 }
1935 }
1936
1937 /* Stage 2: sort starting sectors */
1938 stage2:
1939 for (j = 4; j < partitions-1; j++) {
1940 pj = ptes[j].part_table;
1941 pjj = ptes[j+1].part_table;
1942 sj = get_start_sect(pj);
1943 sjj = get_start_sect(pjj);
1944 oj = ptes[j].offset;
1945 ojj = ptes[j+1].offset;
1946 if (oj+sj > ojj+sjj) {
1947 tmp = *pj;
1948 *pj = *pjj;
1949 *pjj = tmp;
1950 set_start_sect(pj, ojj+sjj-oj);
1951 set_start_sect(pjj, oj+sj-ojj);
1952 goto stage2;
1953 }
1954 }
1955
1956 /* Probably something was changed */
1957 for (j = 4; j < partitions; j++)
1958 ptes[j].changed = 1;
1959}
1960
1961
1962static void
1963fix_partition_table_order(void)
1964{
1965 struct pte *pei, *pek;
1966 int i,k;
1967
1968 if (!wrong_p_order(NULL)) {
1969 printf(_("Nothing to do. Ordering is correct already.\n\n"));
1970 return;
1971 }
1972
1973 while ((i = wrong_p_order(&k)) != 0 && i < 4) {
1974 /* partition i should have come earlier, move it */
1975 /* We have to move data in the MBR */
1976 struct partition *pi, *pk, *pe, pbuf;
1977 pei = &ptes[i];
1978 pek = &ptes[k];
1979
1980 pe = pei->ext_pointer;
1981 pei->ext_pointer = pek->ext_pointer;
1982 pek->ext_pointer = pe;
1983
1984 pi = pei->part_table;
1985 pk = pek->part_table;
1986
1987 memmove(&pbuf, pi, sizeof(struct partition));
1988 memmove(pi, pk, sizeof(struct partition));
1989 memmove(pk, &pbuf, sizeof(struct partition));
1990
1991 pei->changed = pek->changed = 1;
1992 }
1993
1994 if (i)
1995 fix_chain_of_logicals();
1996
1997 printf("Done.\n");
1998
1999}
2000#endif
2001
2002static void
2003list_table(int xtra)
2004{
2005 const struct partition *p;
2006 int i, w;
2007
2008 if (LABEL_IS_SUN) {
2009 sun_list_table(xtra);
2010 return;
2011 }
2012 if (LABEL_IS_SUN) {
2013 sgi_list_table(xtra);
2014 return;
2015 }
2016
2017 list_disk_geometry();
2018
2019 if (LABEL_IS_OSF) {
2020 xbsd_print_disklabel(xtra);
2021 return;
2022 }
2023
2024 /* Heuristic: we list partition 3 of /dev/foo as /dev/foo3,
2025 but if the device name ends in a digit, say /dev/foo1,
2026 then the partition is called /dev/foo1p3. */
2027 w = strlen(disk_device);
2028 if (w && isdigit(disk_device[w-1]))
2029 w++;
2030 if (w < 5)
2031 w = 5;
2032
2033 // 1 12345678901 12345678901 12345678901 12
2034 printf(_("%*s Boot Start End Blocks Id System\n"),
2035 w+1, _("Device"));
2036
2037 for (i = 0; i < partitions; i++) {
2038 const struct pte *pe = &ptes[i];
2039 off_t psects;
2040 off_t pblocks;
2041 unsigned podd;
2042
2043 p = pe->part_table;
2044 if (!p || is_cleared_partition(p))
2045 continue;
2046
2047 psects = get_nr_sects(p);
2048 pblocks = psects;
2049 podd = 0;
2050
2051 if (sector_size < 1024) {
2052 pblocks /= (1024 / sector_size);
2053 podd = psects % (1024 / sector_size);
2054 }
2055 if (sector_size > 1024)
2056 pblocks *= (sector_size / 1024);
2057
2058 printf("%s %c %11llu %11llu %11llu%c %2x %s\n",
2059 partname(disk_device, i+1, w+2),
2060 !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG /* boot flag */
2061 ? '*' : '?',
2062 (unsigned long long) cround(get_partition_start(pe)), /* start */
2063 (unsigned long long) cround(get_partition_start(pe) + psects /* end */
2064 - (psects ? 1 : 0)),
2065 (unsigned long long) pblocks, podd ? '+' : ' ', /* odd flag on end */
2066 p->sys_ind, /* type id */
2067 partition_type(p->sys_ind)); /* type name */
2068
2069 check_consistency(p, i);
2070 }
2071
2072 /* Is partition table in disk order? It need not be, but... */
2073 /* partition table entries are not checked for correct order if this
2074 is a sgi, sun or aix labeled disk... */
2075 if (LABEL_IS_DOS && wrong_p_order(NULL)) {
2076 /* FIXME */
2077 printf(_("\nPartition table entries are not in disk order\n"));
2078 }
2079}
2080
2081#if ENABLE_FEATURE_FDISK_ADVANCED
2082static void
2083x_list_table(int extend)
2084{
2085 const struct pte *pe;
2086 const struct partition *p;
2087 int i;
2088
2089 printf(_("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n"),
2090 disk_device, heads, sectors, cylinders);
2091 printf(_("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"));
2092 for (i = 0 ; i < partitions; i++) {
2093 pe = &ptes[i];
2094 p = (extend ? pe->ext_pointer : pe->part_table);
2095 if (p != NULL) {
2096 printf("%2d %02x%4d%4d%5d%4d%4d%5d%11u%11u %02x\n",
2097 i + 1, p->boot_ind, p->head,
2098 sector(p->sector),
2099 cylinder(p->sector, p->cyl), p->end_head,
2100 sector(p->end_sector),
2101 cylinder(p->end_sector, p->end_cyl),
2102 get_start_sect(p), get_nr_sects(p), p->sys_ind);
2103 if (p->sys_ind)
2104 check_consistency(p, i);
2105 }
2106 }
2107}
2108#endif
2109
2110#if ENABLE_FEATURE_FDISK_WRITABLE
2111static void
2112fill_bounds(off_t *first, off_t *last)
2113{
2114 int i;
2115 const struct pte *pe = &ptes[0];
2116 const struct partition *p;
2117
2118 for (i = 0; i < partitions; pe++,i++) {
2119 p = pe->part_table;
2120 if (!p->sys_ind || IS_EXTENDED(p->sys_ind)) {
2121 first[i] = 0xffffffff;
2122 last[i] = 0;
2123 } else {
2124 first[i] = get_partition_start(pe);
2125 last[i] = first[i] + get_nr_sects(p) - 1;
2126 }
2127 }
2128}
2129
2130static void
2131check(int n, unsigned h, unsigned s, unsigned c, off_t start)
2132{
2133 off_t total, real_s, real_c;
2134
2135 real_s = sector(s) - 1;
2136 real_c = cylinder(s, c);
2137 total = (real_c * sectors + real_s) * heads + h;
2138 if (!total)
2139 printf(_("Warning: partition %d contains sector 0\n"), n);
2140 if (h >= heads)
2141 printf(_("Partition %d: head %d greater than maximum %d\n"),
2142 n, h + 1, heads);
2143 if (real_s >= sectors)
2144 printf(_("Partition %d: sector %d greater than "
2145 "maximum %d\n"), n, s, sectors);
2146 if (real_c >= cylinders)
2147 printf(_("Partitions %d: cylinder %llu greater than "
2148 "maximum %d\n"), n, (unsigned long long)real_c + 1, cylinders);
2149 if (cylinders <= 1024 && start != total)
2150 printf(_("Partition %d: previous sectors %llu disagrees with "
2151 "total %llu\n"), n, (unsigned long long)start, (unsigned long long)total);
2152}
2153
2154static void
2155verify(void)
2156{
2157 int i, j;
2158 unsigned total = 1;
2159 off_t first[partitions], last[partitions];
2160 struct partition *p;
2161
2162 if (warn_geometry())
2163 return;
2164
2165 if (LABEL_IS_SUN) {
2166 verify_sun();
2167 return;
2168 }
2169 if (LABEL_IS_SGI) {
2170 verify_sgi(1);
2171 return;
2172 }
2173
2174 fill_bounds(first, last);
2175 for (i = 0; i < partitions; i++) {
2176 struct pte *pe = &ptes[i];
2177
2178 p = pe->part_table;
2179 if (p->sys_ind && !IS_EXTENDED(p->sys_ind)) {
2180 check_consistency(p, i);
2181 if (get_partition_start(pe) < first[i])
2182 printf(_("Warning: bad start-of-data in "
2183 "partition %d\n"), i + 1);
2184 check(i + 1, p->end_head, p->end_sector, p->end_cyl,
2185 last[i]);
2186 total += last[i] + 1 - first[i];
2187 for (j = 0; j < i; j++)
2188 if ((first[i] >= first[j] && first[i] <= last[j])
2189 || ((last[i] <= last[j] && last[i] >= first[j]))) {
2190 printf(_("Warning: partition %d overlaps "
2191 "partition %d.\n"), j + 1, i + 1);
2192 total += first[i] >= first[j] ?
2193 first[i] : first[j];
2194 total -= last[i] <= last[j] ?
2195 last[i] : last[j];
2196 }
2197 }
2198 }
2199
2200 if (extended_offset) {
2201 struct pte *pex = &ptes[ext_index];
2202 off_t e_last = get_start_sect(pex->part_table) +
2203 get_nr_sects(pex->part_table) - 1;
2204
2205 for (i = 4; i < partitions; i++) {
2206 total++;
2207 p = ptes[i].part_table;
2208 if (!p->sys_ind) {
2209 if (i != 4 || i + 1 < partitions)
2210 printf(_("Warning: partition %d "
2211 "is empty\n"), i + 1);
2212 }
2213 else if (first[i] < extended_offset ||
2214 last[i] > e_last)
2215 printf(_("Logical partition %d not entirely in "
2216 "partition %d\n"), i + 1, ext_index + 1);
2217 }
2218 }
2219
2220 if (total > heads * sectors * cylinders)
2221 printf(_("Total allocated sectors %d greater than the maximum "
2222 "%d\n"), total, heads * sectors * cylinders);
2223 else if ((total = heads * sectors * cylinders - total) != 0)
2224 printf(_("%d unallocated sectors\n"), total);
2225}
2226
2227static void
2228add_partition(int n, int sys)
2229{
2230 char mesg[256]; /* 48 does not suffice in Japanese */
2231 int i, num_read = 0;
2232 struct partition *p = ptes[n].part_table;
2233 struct partition *q = ptes[ext_index].part_table;
2234 long long llimit;
2235 off_t start, stop = 0, limit, temp,
2236 first[partitions], last[partitions];
2237
2238 if (p && p->sys_ind) {
2239 printf(_("Partition %d is already defined. Delete "
2240 "it before re-adding it.\n"), n + 1);
2241 return;
2242 }
2243 fill_bounds(first, last);
2244 if (n < 4) {
2245 start = sector_offset;
2246 if (display_in_cyl_units || !total_number_of_sectors)
2247 llimit = heads * sectors * cylinders - 1;
2248 else
2249 llimit = total_number_of_sectors - 1;
2250 limit = llimit;
2251 if (limit != llimit)
2252 limit = 0x7fffffff;
2253 if (extended_offset) {
2254 first[ext_index] = extended_offset;
2255 last[ext_index] = get_start_sect(q) +
2256 get_nr_sects(q) - 1;
2257 }
2258 } else {
2259 start = extended_offset + sector_offset;
2260 limit = get_start_sect(q) + get_nr_sects(q) - 1;
2261 }
2262 if (display_in_cyl_units)
2263 for (i = 0; i < partitions; i++)
2264 first[i] = (cround(first[i]) - 1) * units_per_sector;
2265
2266 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
2267 do {
2268 temp = start;
2269 for (i = 0; i < partitions; i++) {
2270 int lastplusoff;
2271
2272 if (start == ptes[i].offset)
2273 start += sector_offset;
2274 lastplusoff = last[i] + ((n < 4) ? 0 : sector_offset);
2275 if (start >= first[i] && start <= lastplusoff)
2276 start = lastplusoff + 1;
2277 }
2278 if (start > limit)
2279 break;
2280 if (start >= temp+units_per_sector && num_read) {
2281 printf(_("Sector %"OFF_FMT"d is already allocated\n"), temp);
2282 temp = start;
2283 num_read = 0;
2284 }
2285 if (!num_read && start == temp) {
2286 off_t saved_start;
2287
2288 saved_start = start;
2289 start = read_int(cround(saved_start), cround(saved_start), cround(limit),
2290 0, mesg);
2291 if (display_in_cyl_units) {
2292 start = (start - 1) * units_per_sector;
2293 if (start < saved_start) start = saved_start;
2294 }
2295 num_read = 1;
2296 }
2297 } while (start != temp || !num_read);
2298 if (n > 4) { /* NOT for fifth partition */
2299 struct pte *pe = &ptes[n];
2300
2301 pe->offset = start - sector_offset;
2302 if (pe->offset == extended_offset) { /* must be corrected */
2303 pe->offset++;
2304 if (sector_offset == 1)
2305 start++;
2306 }
2307 }
2308
2309 for (i = 0; i < partitions; i++) {
2310 struct pte *pe = &ptes[i];
2311
2312 if (start < pe->offset && limit >= pe->offset)
2313 limit = pe->offset - 1;
2314 if (start < first[i] && limit >= first[i])
2315 limit = first[i] - 1;
2316 }
2317 if (start > limit) {
2318 printf(_("No free sectors available\n"));
2319 if (n > 4)
2320 partitions--;
2321 return;
2322 }
2323 if (cround(start) == cround(limit)) {
2324 stop = limit;
2325 } else {
2326 snprintf(mesg, sizeof(mesg),
2327 _("Last %s or +size or +sizeM or +sizeK"),
2328 str_units(SINGULAR));
2329 stop = read_int(cround(start), cround(limit), cround(limit),
2330 cround(start), mesg);
2331 if (display_in_cyl_units) {
2332 stop = stop * units_per_sector - 1;
2333 if (stop >limit)
2334 stop = limit;
2335 }
2336 }
2337
2338 set_partition(n, 0, start, stop, sys);
2339 if (n > 4)
2340 set_partition(n - 1, 1, ptes[n].offset, stop, EXTENDED);
2341
2342 if (IS_EXTENDED(sys)) {
2343 struct pte *pe4 = &ptes[4];
2344 struct pte *pen = &ptes[n];
2345
2346 ext_index = n;
2347 pen->ext_pointer = p;
2348 pe4->offset = extended_offset = start;
2349 pe4->sectorbuffer = xzalloc(sector_size);
2350 pe4->part_table = pt_offset(pe4->sectorbuffer, 0);
2351 pe4->ext_pointer = pe4->part_table + 1;
2352 pe4->changed = 1;
2353 partitions = 5;
2354 }
2355}
2356
2357static void
2358add_logical(void)
2359{
2360 if (partitions > 5 || ptes[4].part_table->sys_ind) {
2361 struct pte *pe = &ptes[partitions];
2362
2363 pe->sectorbuffer = xzalloc(sector_size);
2364 pe->part_table = pt_offset(pe->sectorbuffer, 0);
2365 pe->ext_pointer = pe->part_table + 1;
2366 pe->offset = 0;
2367 pe->changed = 1;
2368 partitions++;
2369 }
2370 add_partition(partitions - 1, LINUX_NATIVE);
2371}
2372
2373static void
2374new_partition(void)
2375{
2376 int i, free_primary = 0;
2377
2378 if (warn_geometry())
2379 return;
2380
2381 if (LABEL_IS_SUN) {
2382 add_sun_partition(get_partition(0, partitions), LINUX_NATIVE);
2383 return;
2384 }
2385 if (LABEL_IS_SGI) {
2386 sgi_add_partition(get_partition(0, partitions), LINUX_NATIVE);
2387 return;
2388 }
2389 if (LABEL_IS_AIX) {
2390 printf(_("\tSorry - this fdisk cannot handle AIX disk labels."
2391 "\n\tIf you want to add DOS-type partitions, create"
2392 "\n\ta new empty DOS partition table first. (Use o.)"
2393 "\n\tWARNING: "
2394 "This will destroy the present disk contents.\n"));
2395 return;
2396 }
2397
2398 for (i = 0; i < 4; i++)
2399 free_primary += !ptes[i].part_table->sys_ind;
2400
2401 if (!free_primary && partitions >= MAXIMUM_PARTS) {
2402 printf(_("The maximum number of partitions has been created\n"));
2403 return;
2404 }
2405
2406 if (!free_primary) {
2407 if (extended_offset)
2408 add_logical();
2409 else
2410 printf(_("You must delete some partition and add "
2411 "an extended partition first\n"));
2412 } else {
2413 char c, line[LINE_LENGTH];
2414 snprintf(line, sizeof(line), "%s\n %s\n p primary "
2415 "partition (1-4)\n",
2416 "Command action", (extended_offset ?
2417 "l logical (5 or over)" : "e extended"));
2418 while (1) {
2419 c = read_nonempty(line);
2420 if (c == 'p' || c == 'P') {
2421 i = get_nonexisting_partition(0, 4);
2422 if (i >= 0)
2423 add_partition(i, LINUX_NATIVE);
2424 return;
2425 }
2426 else if (c == 'l' && extended_offset) {
2427 add_logical();
2428 return;
2429 }
2430 else if (c == 'e' && !extended_offset) {
2431 i = get_nonexisting_partition(0, 4);
2432 if (i >= 0)
2433 add_partition(i, EXTENDED);
2434 return;
2435 }
2436 else
2437 printf(_("Invalid partition number "
2438 "for type '%c'\n"), c);
2439 }
2440 }
2441}
2442
2443static void
2444write_table(void)
2445{
2446 int i;
2447
2448 if (LABEL_IS_DOS) {
2449 for (i = 0; i < 3; i++)
2450 if (ptes[i].changed)
2451 ptes[3].changed = 1;
2452 for (i = 3; i < partitions; i++) {
2453 struct pte *pe = &ptes[i];
2454
2455 if (pe->changed) {
2456 write_part_table_flag(pe->sectorbuffer);
2457 write_sector(pe->offset, pe->sectorbuffer);
2458 }
2459 }
2460 }
2461 else if (LABEL_IS_SGI) {
2462 /* no test on change? the printf below might be mistaken */
2463 sgi_write_table();
2464 }
2465 else if (LABEL_IS_SUN) {
2466 int needw = 0;
2467
2468 for (i = 0; i < 8; i++)
2469 if (ptes[i].changed)
2470 needw = 1;
2471 if (needw)
2472 sun_write_table();
2473 }
2474
2475 printf(_("The partition table has been altered!\n\n"));
2476 reread_partition_table(1);
2477}
2478
2479static void
2480reread_partition_table(int leave)
2481{
2482 int error = 0;
2483 int i;
2484
2485 printf(_("Calling ioctl() to re-read partition table.\n"));
2486 sync();
2487 sleep(2);
2488 if ((i = ioctl(fd, BLKRRPART)) != 0) {
2489 error = errno;
2490 } else {
2491 /* some kernel versions (1.2.x) seem to have trouble
2492 rereading the partition table, but if asked to do it
2493 twice, the second time works. - biro@yggdrasil.com */
2494 sync();
2495 sleep(2);
2496 if ((i = ioctl(fd, BLKRRPART)) != 0)
2497 error = errno;
2498 }
2499
2500 if (i) {
2501 printf(_("\nWARNING: Re-reading the partition table "
2502 "failed with error %d: %s.\n"
2503 "The kernel still uses the old table.\n"
2504 "The new table will be used "
2505 "at the next reboot.\n"),
2506 error, strerror(error));
2507 }
2508
2509 if (dos_changed)
2510 printf(
2511 _("\nWARNING: If you have created or modified any DOS 6.x\n"
2512 "partitions, please see the fdisk manual page for additional\n"
2513 "information.\n"));
2514
2515 if (leave) {
2516 close(fd);
2517
2518 printf(_("Syncing disks.\n"));
2519 sync();
2520 sleep(4); /* for sync() */
2521 exit(!!i);
2522 }
2523}
2524#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
2525
2526#if ENABLE_FEATURE_FDISK_ADVANCED
2527#define MAX_PER_LINE 16
2528static void
2529print_buffer(char *pbuffer)
2530{
2531 int i,l;
2532
2533 for (i = 0, l = 0; i < sector_size; i++, l++) {
2534 if (l == 0)
2535 printf("0x%03X:", i);
2536 printf(" %02X", (unsigned char) pbuffer[i]);
2537 if (l == MAX_PER_LINE - 1) {
2538 puts("");
2539 l = -1;
2540 }
2541 }
2542 if (l > 0)
2543 puts("");
2544 puts("");
2545}
2546
2547
2548static void
2549print_raw(void)
2550{
2551 int i;
2552
2553 printf(_("Device: %s\n"), disk_device);
2554 if (LABEL_IS_SGI || LABEL_IS_SUN)
2555 print_buffer(MBRbuffer);
2556 else {
2557 for (i = 3; i < partitions; i++)
2558 print_buffer(ptes[i].sectorbuffer);
2559 }
2560}
2561
2562static void
2563move_begin(int i)
2564{
2565 struct pte *pe = &ptes[i];
2566 struct partition *p = pe->part_table;
2567 off_t new, first;
2568
2569 if (warn_geometry())
2570 return;
2571 if (!p->sys_ind || !get_nr_sects(p) || IS_EXTENDED(p->sys_ind)) {
2572 printf(_("Partition %d has no data area\n"), i + 1);
2573 return;
2574 }
2575 first = get_partition_start(pe);
2576 new = read_int(first, first, first + get_nr_sects(p) - 1, first,
2577 _("New beginning of data")) - pe->offset;
2578
2579 if (new != get_nr_sects(p)) {
2580 first = get_nr_sects(p) + get_start_sect(p) - new;
2581 set_nr_sects(p, first);
2582 set_start_sect(p, new);
2583 pe->changed = 1;
2584 }
2585}
2586
2587static void
2588xselect(void)
2589{
2590 char c;
2591
2592 while (1) {
2593 putchar('\n');
2594 c = tolower(read_nonempty(_("Expert command (m for help): ")));
2595 switch (c) {
2596 case 'a':
2597 if (LABEL_IS_SUN)
2598 sun_set_alt_cyl();
2599 break;
2600 case 'b':
2601 if (LABEL_IS_DOS)
2602 move_begin(get_partition(0, partitions));
2603 break;
2604 case 'c':
2605 user_cylinders = cylinders =
2606 read_int(1, cylinders, 1048576, 0,
2607 _("Number of cylinders"));
2608 if (LABEL_IS_SUN)
2609 sun_set_ncyl(cylinders);
2610 if (LABEL_IS_DOS)
2611 warn_cylinders();
2612 break;
2613 case 'd':
2614 print_raw();
2615 break;
2616 case 'e':
2617 if (LABEL_IS_SGI)
2618 sgi_set_xcyl();
2619 else if (LABEL_IS_SUN)
2620 sun_set_xcyl();
2621 else if (LABEL_IS_DOS)
2622 x_list_table(1);
2623 break;
2624 case 'f':
2625 if (LABEL_IS_DOS)
2626 fix_partition_table_order();
2627 break;
2628 case 'g':
2629#if ENABLE_FEATURE_SGI_LABEL
2630 create_sgilabel();
2631#endif
2632 break;
2633 case 'h':
2634 user_heads = heads = read_int(1, heads, 256, 0,
2635 _("Number of heads"));
2636 update_units();
2637 break;
2638 case 'i':
2639 if (LABEL_IS_SUN)
2640 sun_set_ilfact();
2641 break;
2642 case 'o':
2643 if (LABEL_IS_SUN)
2644 sun_set_rspeed();
2645 break;
2646 case 'p':
2647 if (LABEL_IS_SUN)
2648 list_table(1);
2649 else
2650 x_list_table(0);
2651 break;
2652 case 'q':
2653 close(fd);
2654 puts("");
2655 exit(0);
2656 case 'r':
2657 return;
2658 case 's':
2659 user_sectors = sectors = read_int(1, sectors, 63, 0,
2660 _("Number of sectors"));
2661 if (dos_compatible_flag) {
2662 sector_offset = sectors;
2663 printf(_("Warning: setting sector offset for DOS "
2664 "compatiblity\n"));
2665 }
2666 update_units();
2667 break;
2668 case 'v':
2669 verify();
2670 break;
2671 case 'w':
2672 write_table(); /* does not return */
2673 break;
2674 case 'y':
2675 if (LABEL_IS_SUN)
2676 sun_set_pcylcount();
2677 break;
2678 default:
2679 xmenu();
2680 }
2681 }
2682}
2683#endif /* ADVANCED mode */
2684
2685static int
2686is_ide_cdrom_or_tape(const char *device)
2687{
2688 FILE *procf;
2689 char buf[100];
2690 struct stat statbuf;
2691 int is_ide = 0;
2692
2693 /* No device was given explicitly, and we are trying some
2694 likely things. But opening /dev/hdc may produce errors like
2695 "hdc: tray open or drive not ready"
2696 if it happens to be a CD-ROM drive. It even happens that
2697 the process hangs on the attempt to read a music CD.
2698 So try to be careful. This only works since 2.1.73. */
2699
2700 if (strncmp("/dev/hd", device, 7))
2701 return 0;
2702
2703 snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5);
2704 procf = fopen(buf, "r");
2705 if (procf != NULL && fgets(buf, sizeof(buf), procf))
2706 is_ide = (!strncmp(buf, "cdrom", 5) ||
2707 !strncmp(buf, "tape", 4));
2708 else
2709 /* Now when this proc file does not exist, skip the
2710 device when it is read-only. */
2711 if (stat(device, &statbuf) == 0)
2712 is_ide = ((statbuf.st_mode & 0222) == 0);
2713
2714 if (procf)
2715 fclose(procf);
2716 return is_ide;
2717}
2718
2719
2720static void
2721try(const char *device, int user_specified)
2722{
2723 int gb;
2724
2725 disk_device = device;
2726 if (setjmp(listingbuf))
2727 return;
2728 if (!user_specified)
2729 if (is_ide_cdrom_or_tape(device))
2730 return;
2731 if ((fd = open(disk_device, type_open)) >= 0) {
2732 gb = get_boot(try_only);
2733 if (gb > 0) { /* I/O error */
2734 close(fd);
2735 } else if (gb < 0) { /* no DOS signature */
2736 list_disk_geometry();
2737 if (LABEL_IS_AIX) {
2738 return;
2739 }
2740#if ENABLE_FEATURE_OSF_LABEL
2741 if (btrydev(device) < 0)
2742#endif
2743 printf(_("Disk %s doesn't contain a valid "
2744 "partition table\n"), device);
2745 close(fd);
2746 } else {
2747 close(fd);
2748 list_table(0);
2749#if ENABLE_FEATURE_FDISK_WRITABLE
2750 if (!LABEL_IS_SUN && partitions > 4){
2751 delete_partition(ext_index);
2752 }
2753#endif
2754 }
2755 } else {
2756 /* Ignore other errors, since we try IDE
2757 and SCSI hard disks which may not be
2758 installed on the system. */
2759 if (errno == EACCES) {
2760 printf(_("Cannot open %s\n"), device);
2761 return;
2762 }
2763 }
2764}
2765
2766/* for fdisk -l: try all things in /proc/partitions
2767 that look like a partition name (do not end in a digit) */
2768static void
2769tryprocpt(void)
2770{
2771 FILE *procpt;
2772 char line[100], ptname[100], devname[120], *s;
2773 int ma, mi, sz;
2774
2775 procpt = fopen_or_warn("/proc/partitions", "r");
2776
2777 while (fgets(line, sizeof(line), procpt)) {
2778 if (sscanf(line, " %d %d %d %[^\n ]",
2779 &ma, &mi, &sz, ptname) != 4)
2780 continue;
2781 for (s = ptname; *s; s++);
2782 if (isdigit(s[-1]))
2783 continue;
2784 sprintf(devname, "/dev/%s", ptname);
2785 try(devname, 0);
2786 }
2787#if ENABLE_FEATURE_CLEAN_UP
2788 fclose(procpt);
2789#endif
2790}
2791
2792#if ENABLE_FEATURE_FDISK_WRITABLE
2793static void
2794unknown_command(int c)
2795{
2796 printf(_("%c: unknown command\n"), c);
2797}
2798#endif
2799
2800int fdisk_main(int argc, char **argv)
2801{
2802 char *str_b, *str_C, *str_H, *str_S;
2803 unsigned opt;
2804 int c;
2805 /*
2806 * fdisk -v
2807 * fdisk -l [-b sectorsize] [-u] device ...
2808 * fdisk -s [partition] ...
2809 * fdisk [-b sectorsize] [-u] device
2810 *
2811 * Options -C, -H, -S set the geometry.
2812 */
2813 enum {
2814 OPT_b = 1 << 0,
2815 OPT_C = 1 << 1,
2816 OPT_H = 1 << 2,
2817 OPT_l = 1 << 3,
2818 OPT_S = 1 << 4,
2819 OPT_u = 1 << 5,
2820 OPT_s = (1 << 6) * ENABLE_FEATURE_FDISK_BLKSIZE,
2821 };
2822 opt = getopt32(argc, argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
2823 &str_b, &str_C, &str_H, &str_S);
2824 argc -= optind;
2825 argv += optind;
2826 if (opt & OPT_b) { // -b
2827 /* Ugly: this sector size is really per device,
2828 so cannot be combined with multiple disks,
2829 and the same goes for the C/H/S options.
2830 */
2831 sector_size = xatoi_u(str_b);
2832 if (sector_size != 512 && sector_size != 1024 &&
2833 sector_size != 2048)
2834 bb_show_usage();
2835 sector_offset = 2;
2836 user_set_sector_size = 1;
2837 }
2838 if (opt & OPT_C) user_cylinders = xatoi_u(str_C); // -C
2839 if (opt & OPT_H) { // -H
2840 user_heads = xatoi_u(str_H);
2841 if (user_heads <= 0 || user_heads >= 256)
2842 user_heads = 0;
2843 }
2844 //if (opt & OPT_l) // -l
2845 if (opt & OPT_S) { // -S
2846 user_sectors = xatoi_u(str_S);
2847 if (user_sectors <= 0 || user_sectors >= 64)
2848 user_sectors = 0;
2849 }
2850 if (opt & OPT_u) display_in_cyl_units = 0; // -u
2851 //if (opt & OPT_s) // -s
2852
2853 if (user_set_sector_size && argc != 1)
2854 printf(_("Warning: the -b (set sector size) option should"
2855 " be used with one specified device\n"));
2856
2857#if ENABLE_FEATURE_FDISK_WRITABLE
2858 if (opt & OPT_l) {
2859 nowarn = 1;
2860#endif
2861 type_open = O_RDONLY;
2862 if (argc > 0) {
2863 int k;
2864#if __GNUC__
2865 /* avoid gcc warning:
2866 variable `k' might be clobbered by `longjmp' */
2867 (void)&k;
2868#endif
2869 listing = 1;
2870 for (k = 0; k < argc; k++)
2871 try(argv[k], 1);
2872 } else {
2873 /* we no longer have default device names */
2874 /* but, we can use /proc/partitions instead */
2875 tryprocpt();
2876 }
2877 return 0;
2878#if ENABLE_FEATURE_FDISK_WRITABLE
2879 }
2880#endif
2881
2882#if ENABLE_FEATURE_FDISK_BLKSIZE
2883 if (opt & OPT_s) {
2884 long size;
2885 int j;
2886
2887 nowarn = 1;
2888 type_open = O_RDONLY;
2889
2890 if (argc <= 0)
2891 bb_show_usage();
2892
2893 for (j = 0; j < argc; j++) {
2894 disk_device = argv[j];
2895 fd = open(disk_device, type_open);
2896 if (fd < 0)
2897 fdisk_fatal(unable_to_open);
2898 if (ioctl(fd, BLKGETSIZE, &size))
2899 fdisk_fatal(ioctl_error);
2900 close(fd);
2901 if (argc == 1)
2902 printf("%ld\n", size/2);
2903 else
2904 printf("%s: %ld\n", argv[j], size/2);
2905 }
2906 return 0;
2907 }
2908#endif
2909
2910#if ENABLE_FEATURE_FDISK_WRITABLE
2911 if (argc != 1)
2912 bb_show_usage();
2913
2914 disk_device = argv[0];
2915 get_boot(fdisk);
2916
2917 if (LABEL_IS_OSF) {
2918 /* OSF label, and no DOS label */
2919 printf(_("Detected an OSF/1 disklabel on %s, entering "
2920 "disklabel mode.\n"), disk_device);
2921 bsd_select();
2922 /*Why do we do this? It seems to be counter-intuitive*/
2923 current_label_type = label_dos;
2924 /* If we return we may want to make an empty DOS label? */
2925 }
2926
2927 while (1) {
2928 putchar('\n');
2929 c = tolower(read_nonempty(_("Command (m for help): ")));
2930 switch (c) {
2931 case 'a':
2932 if (LABEL_IS_DOS)
2933 toggle_active(get_partition(1, partitions));
2934 else if (LABEL_IS_SUN)
2935 toggle_sunflags(get_partition(1, partitions),
2936 0x01);
2937 else if (LABEL_IS_SGI)
2938 sgi_set_bootpartition(
2939 get_partition(1, partitions));
2940 else
2941 unknown_command(c);
2942 break;
2943 case 'b':
2944 if (LABEL_IS_SGI) {
2945 printf(_("\nThe current boot file is: %s\n"),
2946 sgi_get_bootfile());
2947 if (read_maybe_empty(_("Please enter the name of the "
2948 "new boot file: ")) == '\n')
2949 printf(_("Boot file unchanged\n"));
2950 else
2951 sgi_set_bootfile(line_ptr);
2952 }
2953#if ENABLE_FEATURE_OSF_LABEL
2954 else
2955 bsd_select();
2956#endif
2957 break;
2958 case 'c':
2959 if (LABEL_IS_DOS)
2960 toggle_dos_compatibility_flag();
2961 else if (LABEL_IS_SUN)
2962 toggle_sunflags(get_partition(1, partitions),
2963 0x10);
2964 else if (LABEL_IS_SGI)
2965 sgi_set_swappartition(
2966 get_partition(1, partitions));
2967 else
2968 unknown_command(c);
2969 break;
2970 case 'd':
2971 {
2972 int j;
2973 /* If sgi_label then don't use get_existing_partition,
2974 let the user select a partition, since
2975 get_existing_partition() only works for Linux-like
2976 partition tables */
2977 if (!LABEL_IS_SGI) {
2978 j = get_existing_partition(1, partitions);
2979 } else {
2980 j = get_partition(1, partitions);
2981 }
2982 if (j >= 0)
2983 delete_partition(j);
2984 }
2985 break;
2986 case 'i':
2987 if (LABEL_IS_SGI)
2988 create_sgiinfo();
2989 else
2990 unknown_command(c);
2991 case 'l':
2992 list_types(get_sys_types());
2993 break;
2994 case 'm':
2995 menu();
2996 break;
2997 case 'n':
2998 new_partition();
2999 break;
3000 case 'o':
3001 create_doslabel();
3002 break;
3003 case 'p':
3004 list_table(0);
3005 break;
3006 case 'q':
3007 close(fd);
3008 puts("");
3009 return 0;
3010 case 's':
3011#if ENABLE_FEATURE_SUN_LABEL
3012 create_sunlabel();
3013#endif
3014 break;
3015 case 't':
3016 change_sysid();
3017 break;
3018 case 'u':
3019 change_units();
3020 break;
3021 case 'v':
3022 verify();
3023 break;
3024 case 'w':
3025 write_table(); /* does not return */
3026 break;
3027#if ENABLE_FEATURE_FDISK_ADVANCED
3028 case 'x':
3029 if (LABEL_IS_SGI) {
3030 printf(_("\n\tSorry, no experts menu for SGI "
3031 "partition tables available.\n\n"));
3032 } else
3033 xselect();
3034 break;
3035#endif
3036 default:
3037 unknown_command(c);
3038 menu();
3039 }
3040 }
3041 return 0;
3042#endif /* CONFIG_FEATURE_FDISK_WRITABLE */
3043}
diff --git a/util-linux/fdisk_aix.c b/util-linux/fdisk_aix.c
new file mode 100644
index 000000000..a3d5fe15f
--- /dev/null
+++ b/util-linux/fdisk_aix.c
@@ -0,0 +1,76 @@
1#ifdef CONFIG_FEATURE_AIX_LABEL
2/*
3 * Copyright (C) Andreas Neuper, Sep 1998.
4 * This file may be redistributed under
5 * the terms of the GNU Public License.
6 */
7
8typedef struct {
9 unsigned int magic; /* expect AIX_LABEL_MAGIC */
10 unsigned int fillbytes1[124];
11 unsigned int physical_volume_id;
12 unsigned int fillbytes2[124];
13} aix_partition;
14
15#define AIX_LABEL_MAGIC 0xc9c2d4c1
16#define AIX_LABEL_MAGIC_SWAPPED 0xc1d4c2c9
17#define AIX_INFO_MAGIC 0x00072959
18#define AIX_INFO_MAGIC_SWAPPED 0x59290700
19
20#define aixlabel ((aix_partition *)MBRbuffer)
21
22
23/*
24 Changes:
25 * 1999-03-20 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
26 * Internationalization
27 *
28 * 2003-03-20 Phillip Kesling <pkesling@sgi.com>
29 * Some fixes
30*/
31
32static int aix_other_endian;
33static short aix_volumes = 1;
34
35/*
36 * only dealing with free blocks here
37 */
38
39static void
40aix_info(void)
41{
42 puts(
43 _("\n\tThere is a valid AIX label on this disk.\n"
44 "\tUnfortunately Linux cannot handle these\n"
45 "\tdisks at the moment. Nevertheless some\n"
46 "\tadvice:\n"
47 "\t1. fdisk will destroy its contents on write.\n"
48 "\t2. Be sure that this disk is NOT a still vital\n"
49 "\t part of a volume group. (Otherwise you may\n"
50 "\t erase the other disks as well, if unmirrored.)\n"
51 "\t3. Before deleting this physical volume be sure\n"
52 "\t to remove the disk logically from your AIX\n"
53 "\t machine. (Otherwise you become an AIXpert).")
54 );
55}
56
57static int
58check_aix_label(void)
59{
60 if (aixlabel->magic != AIX_LABEL_MAGIC &&
61 aixlabel->magic != AIX_LABEL_MAGIC_SWAPPED) {
62 current_label_type = 0;
63 aix_other_endian = 0;
64 return 0;
65 }
66 aix_other_endian = (aixlabel->magic == AIX_LABEL_MAGIC_SWAPPED);
67 update_units();
68 current_label_type = label_aix;
69 partitions = 1016;
70 aix_volumes = 15;
71 aix_info();
72 /*aix_nolabel();*/ /* %% */
73 /*aix_label = 1;*/ /* %% */
74 return 1;
75}
76#endif /* AIX_LABEL */
diff --git a/util-linux/fdisk_osf.c b/util-linux/fdisk_osf.c
new file mode 100644
index 000000000..bff2371e4
--- /dev/null
+++ b/util-linux/fdisk_osf.c
@@ -0,0 +1,1046 @@
1#ifdef CONFIG_FEATURE_OSF_LABEL
2/*
3 * Copyright (c) 1987, 1988 Regents of the University of California.
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 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgment:
16 * This product includes software developed by the University of
17 * California, Berkeley and its contributors.
18 * 4. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35
36#ifndef BSD_DISKMAGIC
37#define BSD_DISKMAGIC ((uint32_t) 0x82564557)
38#endif
39
40#ifndef BSD_MAXPARTITIONS
41#define BSD_MAXPARTITIONS 16
42#endif
43
44#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
45
46#if defined (i386) || defined (__sparc__) || defined (__arm__) || defined (__m68k__) || defined (__mips__) || defined (__s390__) || defined (__sh__) || defined(__x86_64__)
47#define BSD_LABELSECTOR 1
48#define BSD_LABELOFFSET 0
49#elif defined (__alpha__) || defined (__powerpc__) || defined (__ia64__) || defined (__hppa__)
50#define BSD_LABELSECTOR 0
51#define BSD_LABELOFFSET 64
52#elif defined (__s390__) || defined (__s390x__)
53#define BSD_LABELSECTOR 1
54#define BSD_LABELOFFSET 0
55#else
56#error unknown architecture
57#endif
58
59#define BSD_BBSIZE 8192 /* size of boot area, with label */
60#define BSD_SBSIZE 8192 /* max size of fs superblock */
61
62struct xbsd_disklabel {
63 uint32_t d_magic; /* the magic number */
64 int16_t d_type; /* drive type */
65 int16_t d_subtype; /* controller/d_type specific */
66 char d_typename[16]; /* type name, e.g. "eagle" */
67 char d_packname[16]; /* pack identifier */
68 /* disk geometry: */
69 uint32_t d_secsize; /* # of bytes per sector */
70 uint32_t d_nsectors; /* # of data sectors per track */
71 uint32_t d_ntracks; /* # of tracks per cylinder */
72 uint32_t d_ncylinders; /* # of data cylinders per unit */
73 uint32_t d_secpercyl; /* # of data sectors per cylinder */
74 uint32_t d_secperunit; /* # of data sectors per unit */
75 /*
76 * Spares (bad sector replacements) below
77 * are not counted in d_nsectors or d_secpercyl.
78 * Spare sectors are assumed to be physical sectors
79 * which occupy space at the end of each track and/or cylinder.
80 */
81 uint16_t d_sparespertrack; /* # of spare sectors per track */
82 uint16_t d_sparespercyl; /* # of spare sectors per cylinder */
83 /*
84 * Alternate cylinders include maintenance, replacement,
85 * configuration description areas, etc.
86 */
87 uint32_t d_acylinders; /* # of alt. cylinders per unit */
88
89 /* hardware characteristics: */
90 /*
91 * d_interleave, d_trackskew and d_cylskew describe perturbations
92 * in the media format used to compensate for a slow controller.
93 * Interleave is physical sector interleave, set up by the formatter
94 * or controller when formatting. When interleaving is in use,
95 * logically adjacent sectors are not physically contiguous,
96 * but instead are separated by some number of sectors.
97 * It is specified as the ratio of physical sectors traversed
98 * per logical sector. Thus an interleave of 1:1 implies contiguous
99 * layout, while 2:1 implies that logical sector 0 is separated
100 * by one sector from logical sector 1.
101 * d_trackskew is the offset of sector 0 on track N
102 * relative to sector 0 on track N-1 on the same cylinder.
103 * Finally, d_cylskew is the offset of sector 0 on cylinder N
104 * relative to sector 0 on cylinder N-1.
105 */
106 uint16_t d_rpm; /* rotational speed */
107 uint16_t d_interleave; /* hardware sector interleave */
108 uint16_t d_trackskew; /* sector 0 skew, per track */
109 uint16_t d_cylskew; /* sector 0 skew, per cylinder */
110 uint32_t d_headswitch; /* head switch time, usec */
111 uint32_t d_trkseek; /* track-to-track seek, usec */
112 uint32_t d_flags; /* generic flags */
113#define NDDATA 5
114 uint32_t d_drivedata[NDDATA]; /* drive-type specific information */
115#define NSPARE 5
116 uint32_t d_spare[NSPARE]; /* reserved for future use */
117 uint32_t d_magic2; /* the magic number (again) */
118 uint16_t d_checksum; /* xor of data incl. partitions */
119 /* filesystem and partition information: */
120 uint16_t d_npartitions; /* number of partitions in following */
121 uint32_t d_bbsize; /* size of boot area at sn0, bytes */
122 uint32_t d_sbsize; /* max size of fs superblock, bytes */
123 struct xbsd_partition { /* the partition table */
124 uint32_t p_size; /* number of sectors in partition */
125 uint32_t p_offset; /* starting sector */
126 uint32_t p_fsize; /* filesystem basic fragment size */
127 uint8_t p_fstype; /* filesystem type, see below */
128 uint8_t p_frag; /* filesystem fragments per block */
129 uint16_t p_cpg; /* filesystem cylinders per group */
130 } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
131};
132
133/* d_type values: */
134#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */
135#define BSD_DTYPE_MSCP 2 /* MSCP */
136#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */
137#define BSD_DTYPE_SCSI 4 /* SCSI */
138#define BSD_DTYPE_ESDI 5 /* ESDI interface */
139#define BSD_DTYPE_ST506 6 /* ST506 etc. */
140#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */
141#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */
142#define BSD_DTYPE_FLOPPY 10 /* floppy */
143
144/* d_subtype values: */
145#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */
146#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */
147#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */
148
149static const char * const xbsd_dktypenames[] = {
150 "unknown",
151 "SMD",
152 "MSCP",
153 "old DEC",
154 "SCSI",
155 "ESDI",
156 "ST506",
157 "HP-IB",
158 "HP-FL",
159 "type 9",
160 "floppy",
161 0
162};
163#define BSD_DKMAXTYPES (sizeof(xbsd_dktypenames) / sizeof(xbsd_dktypenames[0]) - 1)
164
165/*
166 * Filesystem type and version.
167 * Used to interpret other filesystem-specific
168 * per-partition information.
169 */
170#define BSD_FS_UNUSED 0 /* unused */
171#define BSD_FS_SWAP 1 /* swap */
172#define BSD_FS_V6 2 /* Sixth Edition */
173#define BSD_FS_V7 3 /* Seventh Edition */
174#define BSD_FS_SYSV 4 /* System V */
175#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */
176#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */
177#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */
178#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */
179#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */
180#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */
181#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */
182#define BSD_FS_ISOFS BSD_FS_ISO9660
183#define BSD_FS_BOOT 13 /* partition contains bootstrap */
184#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */
185#define BSD_FS_HFS 15 /* Macintosh HFS */
186#define BSD_FS_ADVFS 16 /* Digital Unix AdvFS */
187
188/* this is annoying, but it's also the way it is :-( */
189#ifdef __alpha__
190#define BSD_FS_EXT2 8 /* ext2 file system */
191#else
192#define BSD_FS_MSDOS 8 /* MS-DOS file system */
193#endif
194
195static const struct systypes xbsd_fstypes[] = {
196 { "\x00" "unused" }, /* BSD_FS_UNUSED */
197 { "\x01" "swap" }, /* BSD_FS_SWAP */
198 { "\x02" "Version 6" }, /* BSD_FS_V6 */
199 { "\x03" "Version 7" }, /* BSD_FS_V7 */
200 { "\x04" "System V" }, /* BSD_FS_SYSV */
201 { "\x05" "4.1BSD" }, /* BSD_FS_V71K */
202 { "\x06" "Eighth Edition" }, /* BSD_FS_V8 */
203 { "\x07" "4.2BSD" }, /* BSD_FS_BSDFFS */
204#ifdef __alpha__
205 { "\x08" "ext2" }, /* BSD_FS_EXT2 */
206#else
207 { "\x08" "MS-DOS" }, /* BSD_FS_MSDOS */
208#endif
209 { "\x09" "4.4LFS" }, /* BSD_FS_BSDLFS */
210 { "\x0a" "unknown" }, /* BSD_FS_OTHER */
211 { "\x0b" "HPFS" }, /* BSD_FS_HPFS */
212 { "\x0c" "ISO-9660" }, /* BSD_FS_ISO9660 */
213 { "\x0d" "boot" }, /* BSD_FS_BOOT */
214 { "\x0e" "ADOS" }, /* BSD_FS_ADOS */
215 { "\x0f" "HFS" }, /* BSD_FS_HFS */
216 { "\x10" "AdvFS" }, /* BSD_FS_ADVFS */
217 { NULL }
218};
219#define BSD_FSMAXTYPES (SIZE(xbsd_fstypes)-1)
220
221
222/*
223 * flags shared by various drives:
224 */
225#define BSD_D_REMOVABLE 0x01 /* removable media */
226#define BSD_D_ECC 0x02 /* supports ECC */
227#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */
228#define BSD_D_RAMDISK 0x08 /* disk emulator */
229#define BSD_D_CHAIN 0x10 /* can do back-back transfers */
230#define BSD_D_DOSPART 0x20 /* within MSDOS partition */
231
232/*
233 Changes:
234 19990319 - Arnaldo Carvalho de Melo <acme@conectiva.com.br> - i18n/nls
235
236 20000101 - David Huggins-Daines <dhuggins@linuxcare.com> - Better
237 support for OSF/1 disklabels on Alpha.
238 Also fixed unaligned accesses in alpha_bootblock_checksum()
239*/
240
241static int possibly_osf_label;
242
243#define FREEBSD_PARTITION 0xa5
244#define NETBSD_PARTITION 0xa9
245
246static void xbsd_delete_part(void);
247static void xbsd_new_part(void);
248static void xbsd_write_disklabel(void);
249static int xbsd_create_disklabel(void);
250static void xbsd_edit_disklabel(void);
251static void xbsd_write_bootstrap(void);
252static void xbsd_change_fstype(void);
253static int xbsd_get_part_index(int max);
254static int xbsd_check_new_partition(int *i);
255static void xbsd_list_types(void);
256static u_short xbsd_dkcksum(struct xbsd_disklabel *lp);
257static int xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d);
258static int xbsd_readlabel(struct partition *p, struct xbsd_disklabel *d);
259static int xbsd_writelabel(struct partition *p, struct xbsd_disklabel *d);
260
261#if defined (__alpha__)
262static void alpha_bootblock_checksum(char *boot);
263#endif
264
265#if !defined (__alpha__)
266static int xbsd_translate_fstype(int linux_type);
267static void xbsd_link_part(void);
268static struct partition *xbsd_part;
269static int xbsd_part_index;
270#endif
271
272#if defined (__alpha__)
273/* We access this through a uint64_t * when checksumming */
274static char disklabelbuffer[BSD_BBSIZE] ATTRIBUTE_ALIGNED(8);
275#else
276static char disklabelbuffer[BSD_BBSIZE];
277#endif
278
279static struct xbsd_disklabel xbsd_dlabel;
280
281#define bsd_cround(n) \
282 (display_in_cyl_units ? ((n)/xbsd_dlabel.d_secpercyl) + 1 : (n))
283
284/*
285 * Test whether the whole disk has BSD disk label magic.
286 *
287 * Note: often reformatting with DOS-type label leaves the BSD magic,
288 * so this does not mean that there is a BSD disk label.
289 */
290static int
291check_osf_label(void)
292{
293 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
294 return 0;
295 return 1;
296}
297
298static int
299btrydev(const char * dev)
300{
301 if (xbsd_readlabel (NULL, &xbsd_dlabel) == 0)
302 return -1;
303 printf(_("\nBSD label for device: %s\n"), dev);
304 xbsd_print_disklabel (0);
305 return 0;
306}
307
308static void
309bmenu(void)
310{
311 puts (_("Command action"));
312 puts (_("\td\tdelete a BSD partition"));
313 puts (_("\te\tedit drive data"));
314 puts (_("\ti\tinstall bootstrap"));
315 puts (_("\tl\tlist known filesystem types"));
316 puts (_("\tm\tprint this menu"));
317 puts (_("\tn\tadd a new BSD partition"));
318 puts (_("\tp\tprint BSD partition table"));
319 puts (_("\tq\tquit without saving changes"));
320 puts (_("\tr\treturn to main menu"));
321 puts (_("\ts\tshow complete disklabel"));
322 puts (_("\tt\tchange a partition's filesystem id"));
323 puts (_("\tu\tchange units (cylinders/sectors)"));
324 puts (_("\tw\twrite disklabel to disk"));
325#if !defined (__alpha__)
326 puts (_("\tx\tlink BSD partition to non-BSD partition"));
327#endif
328}
329
330#if !defined (__alpha__)
331static int
332hidden(int type)
333{
334 return type ^ 0x10;
335}
336
337static int
338is_bsd_partition_type(int type)
339{
340 return (type == FREEBSD_PARTITION ||
341 type == hidden(FREEBSD_PARTITION) ||
342 type == NETBSD_PARTITION ||
343 type == hidden(NETBSD_PARTITION));
344}
345#endif
346
347static void
348bsd_select(void)
349{
350#if !defined (__alpha__)
351 int t, ss;
352 struct partition *p;
353
354 for (t = 0; t < 4; t++) {
355 p = get_part_table(t);
356 if (p && is_bsd_partition_type(p->sys_ind)) {
357 xbsd_part = p;
358 xbsd_part_index = t;
359 ss = get_start_sect(xbsd_part);
360 if (ss == 0) {
361 fprintf(stderr, _("Partition %s has invalid starting sector 0.\n"),
362 partname(disk_device, t+1, 0));
363 return;
364 }
365 printf(_("Reading disklabel of %s at sector %d.\n"),
366 partname(disk_device, t+1, 0), ss + BSD_LABELSECTOR);
367 if (xbsd_readlabel(xbsd_part, &xbsd_dlabel) == 0)
368 if (xbsd_create_disklabel() == 0)
369 return;
370 break;
371 }
372 }
373
374 if (t == 4) {
375 printf(_("There is no *BSD partition on %s.\n"), disk_device);
376 return;
377 }
378
379#elif defined (__alpha__)
380
381 if (xbsd_readlabel(NULL, &xbsd_dlabel) == 0)
382 if (xbsd_create_disklabel() == 0)
383 exit (EXIT_SUCCESS);
384
385#endif
386
387 while (1) {
388 putchar('\n');
389 switch (tolower(read_nonempty(_("BSD disklabel command (m for help): ")))) {
390 case 'd':
391 xbsd_delete_part();
392 break;
393 case 'e':
394 xbsd_edit_disklabel();
395 break;
396 case 'i':
397 xbsd_write_bootstrap();
398 break;
399 case 'l':
400 xbsd_list_types();
401 break;
402 case 'n':
403 xbsd_new_part();
404 break;
405 case 'p':
406 xbsd_print_disklabel(0);
407 break;
408 case 'q':
409 close(fd);
410 exit(EXIT_SUCCESS);
411 case 'r':
412 return;
413 case 's':
414 xbsd_print_disklabel(1);
415 break;
416 case 't':
417 xbsd_change_fstype();
418 break;
419 case 'u':
420 change_units();
421 break;
422 case 'w':
423 xbsd_write_disklabel();
424 break;
425#if !defined (__alpha__)
426 case 'x':
427 xbsd_link_part();
428 break;
429#endif
430 default:
431 bmenu();
432 break;
433 }
434 }
435}
436
437static void
438xbsd_delete_part(void)
439{
440 int i;
441
442 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
443 xbsd_dlabel.d_partitions[i].p_size = 0;
444 xbsd_dlabel.d_partitions[i].p_offset = 0;
445 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
446 if (xbsd_dlabel.d_npartitions == i + 1)
447 while (xbsd_dlabel.d_partitions[xbsd_dlabel.d_npartitions-1].p_size == 0)
448 xbsd_dlabel.d_npartitions--;
449}
450
451static void
452xbsd_new_part(void)
453{
454 off_t begin, end;
455 char mesg[256];
456 int i;
457
458 if (!xbsd_check_new_partition(&i))
459 return;
460
461#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
462 begin = get_start_sect(xbsd_part);
463 end = begin + get_nr_sects(xbsd_part) - 1;
464#else
465 begin = 0;
466 end = xbsd_dlabel.d_secperunit - 1;
467#endif
468
469 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
470 begin = read_int(bsd_cround(begin), bsd_cround(begin), bsd_cround(end),
471 0, mesg);
472
473 if (display_in_cyl_units)
474 begin = (begin - 1) * xbsd_dlabel.d_secpercyl;
475
476 snprintf(mesg, sizeof(mesg), _("Last %s or +size or +sizeM or +sizeK"),
477 str_units(SINGULAR));
478 end = read_int(bsd_cround (begin), bsd_cround (end), bsd_cround (end),
479 bsd_cround (begin), mesg);
480
481 if (display_in_cyl_units)
482 end = end * xbsd_dlabel.d_secpercyl - 1;
483
484 xbsd_dlabel.d_partitions[i].p_size = end - begin + 1;
485 xbsd_dlabel.d_partitions[i].p_offset = begin;
486 xbsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED;
487}
488
489static void
490xbsd_print_disklabel(int show_all)
491{
492 struct xbsd_disklabel *lp = &xbsd_dlabel;
493 struct xbsd_partition *pp;
494 int i, j;
495
496 if (show_all) {
497#if defined (__alpha__)
498 printf("# %s:\n", disk_device);
499#else
500 printf("# %s:\n", partname(disk_device, xbsd_part_index+1, 0));
501#endif
502 if ((unsigned) lp->d_type < BSD_DKMAXTYPES)
503 printf(_("type: %s\n"), xbsd_dktypenames[lp->d_type]);
504 else
505 printf(_("type: %d\n"), lp->d_type);
506 printf(_("disk: %.*s\n"), (int) sizeof(lp->d_typename), lp->d_typename);
507 printf(_("label: %.*s\n"), (int) sizeof(lp->d_packname), lp->d_packname);
508 printf(_("flags:"));
509 if (lp->d_flags & BSD_D_REMOVABLE)
510 printf(_(" removable"));
511 if (lp->d_flags & BSD_D_ECC)
512 printf(_(" ecc"));
513 if (lp->d_flags & BSD_D_BADSECT)
514 printf(_(" badsect"));
515 puts("");
516 /* On various machines the fields of *lp are short/int/long */
517 /* In order to avoid problems, we cast them all to long. */
518 printf(_("bytes/sector: %ld\n"), (long) lp->d_secsize);
519 printf(_("sectors/track: %ld\n"), (long) lp->d_nsectors);
520 printf(_("tracks/cylinder: %ld\n"), (long) lp->d_ntracks);
521 printf(_("sectors/cylinder: %ld\n"), (long) lp->d_secpercyl);
522 printf(_("cylinders: %ld\n"), (long) lp->d_ncylinders);
523 printf(_("rpm: %d\n"), lp->d_rpm);
524 printf(_("interleave: %d\n"), lp->d_interleave);
525 printf(_("trackskew: %d\n"), lp->d_trackskew);
526 printf(_("cylinderskew: %d\n"), lp->d_cylskew);
527 printf(_("headswitch: %ld\t\t# milliseconds\n"),
528 (long) lp->d_headswitch);
529 printf(_("track-to-track seek: %ld\t# milliseconds\n"),
530 (long) lp->d_trkseek);
531 printf(_("drivedata: "));
532 for (i = NDDATA - 1; i >= 0; i--)
533 if (lp->d_drivedata[i])
534 break;
535 if (i < 0)
536 i = 0;
537 for (j = 0; j <= i; j++)
538 printf("%ld ", (long) lp->d_drivedata[j]);
539 }
540 printf(_("\n%d partitions:\n"), lp->d_npartitions);
541 printf(_("# start end size fstype [fsize bsize cpg]\n"));
542 pp = lp->d_partitions;
543 for (i = 0; i < lp->d_npartitions; i++, pp++) {
544 if (pp->p_size) {
545 if (display_in_cyl_units && lp->d_secpercyl) {
546 printf(" %c: %8ld%c %8ld%c %8ld%c ",
547 'a' + i,
548 (long) pp->p_offset / lp->d_secpercyl + 1,
549 (pp->p_offset % lp->d_secpercyl) ? '*' : ' ',
550 (long) (pp->p_offset + pp->p_size + lp->d_secpercyl - 1) / lp->d_secpercyl,
551 ((pp->p_offset + pp->p_size) % lp->d_secpercyl) ? '*' : ' ',
552 (long) pp->p_size / lp->d_secpercyl,
553 (pp->p_size % lp->d_secpercyl) ? '*' : ' '
554 );
555 } else {
556 printf(" %c: %8ld %8ld %8ld ",
557 'a' + i,
558 (long) pp->p_offset,
559 (long) pp->p_offset + pp->p_size - 1,
560 (long) pp->p_size
561 );
562 }
563
564 if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES)
565 printf("%8.8s", xbsd_fstypes[pp->p_fstype].name);
566 else
567 printf("%8x", pp->p_fstype);
568
569 switch (pp->p_fstype) {
570 case BSD_FS_UNUSED:
571 printf(" %5ld %5ld %5.5s ",
572 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, "");
573 break;
574 case BSD_FS_BSDFFS:
575 printf(" %5ld %5ld %5d ",
576 (long) pp->p_fsize, (long) pp->p_fsize * pp->p_frag, pp->p_cpg);
577 break;
578 default:
579 printf("%22.22s", "");
580 break;
581 }
582 puts("");
583 }
584 }
585}
586
587static void
588xbsd_write_disklabel(void)
589{
590#if defined (__alpha__)
591 printf(_("Writing disklabel to %s.\n"), disk_device);
592 xbsd_writelabel(NULL, &xbsd_dlabel);
593#else
594 printf(_("Writing disklabel to %s.\n"),
595 partname(disk_device, xbsd_part_index + 1, 0));
596 xbsd_writelabel(xbsd_part, &xbsd_dlabel);
597#endif
598 reread_partition_table(0); /* no exit yet */
599}
600
601static int
602xbsd_create_disklabel(void)
603{
604 char c;
605
606#if defined (__alpha__)
607 fprintf(stderr, _("%s contains no disklabel.\n"), disk_device);
608#else
609 fprintf(stderr, _("%s contains no disklabel.\n"),
610 partname(disk_device, xbsd_part_index + 1, 0));
611#endif
612
613 while (1) {
614 c = read_nonempty(_("Do you want to create a disklabel? (y/n) "));
615 if (c == 'y' || c == 'Y') {
616 if (xbsd_initlabel(
617#if defined (__alpha__) || defined (__powerpc__) || defined (__hppa__) || \
618 defined (__s390__) || defined (__s390x__)
619 NULL, &xbsd_dlabel
620#else
621 xbsd_part, &xbsd_dlabel/* not used, xbsd_part_index*/
622#endif
623 ) == 1) {
624 xbsd_print_disklabel (1);
625 return 1;
626 } else
627 return 0;
628 } else if (c == 'n')
629 return 0;
630 }
631}
632
633static int
634edit_int(int def, char *mesg)
635{
636 do {
637 fputs(mesg, stdout);
638 printf(" (%d): ", def);
639 if (!read_line())
640 return def;
641 } while (!isdigit(*line_ptr));
642 return atoi(line_ptr);
643}
644
645static void
646xbsd_edit_disklabel(void)
647{
648 struct xbsd_disklabel *d;
649
650 d = &xbsd_dlabel;
651
652#if defined (__alpha__) || defined (__ia64__)
653 d->d_secsize = (u_long) edit_int((u_long) d->d_secsize ,_("bytes/sector"));
654 d->d_nsectors = (u_long) edit_int((u_long) d->d_nsectors ,_("sectors/track"));
655 d->d_ntracks = (u_long) edit_int((u_long) d->d_ntracks ,_("tracks/cylinder"));
656 d->d_ncylinders = (u_long) edit_int((u_long) d->d_ncylinders ,_("cylinders"));
657#endif
658
659 /* d->d_secpercyl can be != d->d_nsectors * d->d_ntracks */
660 while (1) {
661 d->d_secpercyl = (u_long) edit_int((u_long) d->d_nsectors * d->d_ntracks,
662 _("sectors/cylinder"));
663 if (d->d_secpercyl <= d->d_nsectors * d->d_ntracks)
664 break;
665
666 printf(_("Must be <= sectors/track * tracks/cylinder (default).\n"));
667 }
668 d->d_rpm = (u_short) edit_int((u_short) d->d_rpm ,_("rpm"));
669 d->d_interleave = (u_short) edit_int((u_short) d->d_interleave,_("interleave"));
670 d->d_trackskew = (u_short) edit_int((u_short) d->d_trackskew ,_("trackskew"));
671 d->d_cylskew = (u_short) edit_int((u_short) d->d_cylskew ,_("cylinderskew"));
672 d->d_headswitch = (u_long) edit_int((u_long) d->d_headswitch ,_("headswitch"));
673 d->d_trkseek = (u_long) edit_int((u_long) d->d_trkseek ,_("track-to-track seek"));
674
675 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
676}
677
678static int
679xbsd_get_bootstrap (char *path, void *ptr, int size)
680{
681 int fdb;
682
683 if ((fdb = open (path, O_RDONLY)) < 0) {
684 perror(path);
685 return 0;
686 }
687 if (read(fdb, ptr, size) < 0) {
688 perror(path);
689 close(fdb);
690 return 0;
691 }
692 printf(" ... %s\n", path);
693 close(fdb);
694 return 1;
695}
696
697static void
698sync_disks(void)
699{
700 printf(_("\nSyncing disks.\n"));
701 sync();
702 sleep(4); /* What? */
703}
704
705static void
706xbsd_write_bootstrap(void)
707{
708 char *bootdir = BSD_LINUX_BOOTDIR;
709 char path[MAXPATHLEN];
710 char *dkbasename;
711 struct xbsd_disklabel dl;
712 char *d, *p, *e;
713 int sector;
714
715 if (xbsd_dlabel.d_type == BSD_DTYPE_SCSI)
716 dkbasename = "sd";
717 else
718 dkbasename = "wd";
719
720 printf(_("Bootstrap: %sboot -> boot%s (%s): "),
721 dkbasename, dkbasename, dkbasename);
722 if (read_line()) {
723 line_ptr[strlen(line_ptr)-1] = '\0';
724 dkbasename = line_ptr;
725 }
726 snprintf(path, sizeof(path), "%s/%sboot", bootdir, dkbasename);
727 if (!xbsd_get_bootstrap(path, disklabelbuffer, (int) xbsd_dlabel.d_secsize))
728 return;
729
730/* We need a backup of the disklabel (xbsd_dlabel might have changed). */
731 d = &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE];
732 memmove(&dl, d, sizeof(struct xbsd_disklabel));
733
734/* The disklabel will be overwritten by 0's from bootxx anyway */
735 memset(d, 0, sizeof(struct xbsd_disklabel));
736
737 snprintf(path, sizeof(path), "%s/boot%s", bootdir, dkbasename);
738 if (!xbsd_get_bootstrap(path, &disklabelbuffer[xbsd_dlabel.d_secsize],
739 (int) xbsd_dlabel.d_bbsize - xbsd_dlabel.d_secsize))
740 return;
741
742 e = d + sizeof(struct xbsd_disklabel);
743 for (p = d; p < e; p++)
744 if (*p) {
745 fprintf(stderr, _("Bootstrap overlaps with disk label!\n"));
746 exit(EXIT_FAILURE);
747 }
748
749 memmove(d, &dl, sizeof(struct xbsd_disklabel));
750
751#if defined (__powerpc__) || defined (__hppa__)
752 sector = 0;
753#elif defined (__alpha__)
754 sector = 0;
755 alpha_bootblock_checksum(disklabelbuffer);
756#else
757 sector = get_start_sect(xbsd_part);
758#endif
759
760 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
761 fdisk_fatal(unable_to_seek);
762 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
763 fdisk_fatal(unable_to_write);
764
765#if defined (__alpha__)
766 printf(_("Bootstrap installed on %s.\n"), disk_device);
767#else
768 printf(_("Bootstrap installed on %s.\n"),
769 partname (disk_device, xbsd_part_index+1, 0));
770#endif
771
772 sync_disks();
773}
774
775static void
776xbsd_change_fstype(void)
777{
778 int i;
779
780 i = xbsd_get_part_index(xbsd_dlabel.d_npartitions);
781 xbsd_dlabel.d_partitions[i].p_fstype = read_hex(xbsd_fstypes);
782}
783
784static int
785xbsd_get_part_index(int max)
786{
787 char prompt[256];
788 char l;
789
790 snprintf(prompt, sizeof(prompt), _("Partition (a-%c): "), 'a' + max - 1);
791 do
792 l = tolower(read_nonempty(prompt));
793 while (l < 'a' || l > 'a' + max - 1);
794 return l - 'a';
795}
796
797static int
798xbsd_check_new_partition(int *i)
799{
800 /* room for more? various BSD flavours have different maxima */
801 if (xbsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) {
802 int t;
803
804 for (t = 0; t < BSD_MAXPARTITIONS; t++)
805 if (xbsd_dlabel.d_partitions[t].p_size == 0)
806 break;
807
808 if (t == BSD_MAXPARTITIONS) {
809 fprintf(stderr, _("The maximum number of partitions "
810 "has been created\n"));
811 return 0;
812 }
813 }
814
815 *i = xbsd_get_part_index (BSD_MAXPARTITIONS);
816
817 if (*i >= xbsd_dlabel.d_npartitions)
818 xbsd_dlabel.d_npartitions = (*i) + 1;
819
820 if (xbsd_dlabel.d_partitions[*i].p_size != 0) {
821 fprintf(stderr, _("This partition already exists.\n"));
822 return 0;
823 }
824
825 return 1;
826}
827
828static void
829xbsd_list_types(void)
830{
831 list_types(xbsd_fstypes);
832}
833
834static u_short
835xbsd_dkcksum(struct xbsd_disklabel *lp)
836{
837 u_short *start, *end;
838 u_short sum = 0;
839
840 start = (u_short *) lp;
841 end = (u_short *) &lp->d_partitions[lp->d_npartitions];
842 while (start < end)
843 sum ^= *start++;
844 return sum;
845}
846
847static int
848xbsd_initlabel(struct partition *p, struct xbsd_disklabel *d)
849{
850 struct xbsd_partition *pp;
851
852 get_geometry();
853 memset(d, 0, sizeof(struct xbsd_disklabel));
854
855 d->d_magic = BSD_DISKMAGIC;
856
857 if (strncmp(disk_device, "/dev/sd", 7) == 0)
858 d->d_type = BSD_DTYPE_SCSI;
859 else
860 d->d_type = BSD_DTYPE_ST506;
861
862#if !defined (__alpha__)
863 d->d_flags = BSD_D_DOSPART;
864#else
865 d->d_flags = 0;
866#endif
867 d->d_secsize = SECTOR_SIZE; /* bytes/sector */
868 d->d_nsectors = sectors; /* sectors/track */
869 d->d_ntracks = heads; /* tracks/cylinder (heads) */
870 d->d_ncylinders = cylinders;
871 d->d_secpercyl = sectors * heads;/* sectors/cylinder */
872 if (d->d_secpercyl == 0)
873 d->d_secpercyl = 1; /* avoid segfaults */
874 d->d_secperunit = d->d_secpercyl * d->d_ncylinders;
875
876 d->d_rpm = 3600;
877 d->d_interleave = 1;
878 d->d_trackskew = 0;
879 d->d_cylskew = 0;
880 d->d_headswitch = 0;
881 d->d_trkseek = 0;
882
883 d->d_magic2 = BSD_DISKMAGIC;
884 d->d_bbsize = BSD_BBSIZE;
885 d->d_sbsize = BSD_SBSIZE;
886
887#if !defined (__alpha__)
888 d->d_npartitions = 4;
889 pp = &d->d_partitions[2]; /* Partition C should be
890 the NetBSD partition */
891 pp->p_offset = get_start_sect(p);
892 pp->p_size = get_nr_sects(p);
893 pp->p_fstype = BSD_FS_UNUSED;
894 pp = &d->d_partitions[3]; /* Partition D should be
895 the whole disk */
896 pp->p_offset = 0;
897 pp->p_size = d->d_secperunit;
898 pp->p_fstype = BSD_FS_UNUSED;
899#elif defined (__alpha__)
900 d->d_npartitions = 3;
901 pp = &d->d_partitions[2]; /* Partition C should be
902 the whole disk */
903 pp->p_offset = 0;
904 pp->p_size = d->d_secperunit;
905 pp->p_fstype = BSD_FS_UNUSED;
906#endif
907
908 return 1;
909}
910
911/*
912 * Read a xbsd_disklabel from sector 0 or from the starting sector of p.
913 * If it has the right magic, return 1.
914 */
915static int
916xbsd_readlabel (struct partition *p, struct xbsd_disklabel *d)
917{
918 int t, sector;
919
920 /* p is used only to get the starting sector */
921#if !defined (__alpha__)
922 sector = (p ? get_start_sect(p) : 0);
923#elif defined (__alpha__)
924 sector = 0;
925#endif
926
927 if (lseek(fd, sector * SECTOR_SIZE, SEEK_SET) == -1)
928 fdisk_fatal(unable_to_seek);
929 if (BSD_BBSIZE != read(fd, disklabelbuffer, BSD_BBSIZE))
930 fdisk_fatal(unable_to_read);
931
932 memmove(d, &disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
933 sizeof(struct xbsd_disklabel));
934
935 if (d->d_magic != BSD_DISKMAGIC || d->d_magic2 != BSD_DISKMAGIC)
936 return 0;
937
938 for (t = d->d_npartitions; t < BSD_MAXPARTITIONS; t++) {
939 d->d_partitions[t].p_size = 0;
940 d->d_partitions[t].p_offset = 0;
941 d->d_partitions[t].p_fstype = BSD_FS_UNUSED;
942 }
943
944 if (d->d_npartitions > BSD_MAXPARTITIONS)
945 fprintf(stderr, _("Warning: too many partitions "
946 "(%d, maximum is %d).\n"),
947 d->d_npartitions, BSD_MAXPARTITIONS);
948 return 1;
949}
950
951static int
952xbsd_writelabel (struct partition *p, struct xbsd_disklabel *d)
953{
954 unsigned int sector;
955
956#if !defined (__alpha__) && !defined (__powerpc__) && !defined (__hppa__)
957 sector = get_start_sect(p) + BSD_LABELSECTOR;
958#else
959 sector = BSD_LABELSECTOR;
960#endif
961
962 d->d_checksum = 0;
963 d->d_checksum = xbsd_dkcksum (d);
964
965 /* This is necessary if we want to write the bootstrap later,
966 otherwise we'd write the old disklabel with the bootstrap.
967 */
968 memmove(&disklabelbuffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET],
969 d, sizeof(struct xbsd_disklabel));
970
971#if defined (__alpha__) && BSD_LABELSECTOR == 0
972 alpha_bootblock_checksum(disklabelbuffer);
973 if (lseek(fd, 0, SEEK_SET) == -1)
974 fdisk_fatal(unable_to_seek);
975 if (BSD_BBSIZE != write(fd, disklabelbuffer, BSD_BBSIZE))
976 fdisk_fatal(unable_to_write);
977#else
978 if (lseek(fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1)
979 fdisk_fatal(unable_to_seek);
980 if (sizeof(struct xbsd_disklabel) != write(fd, d, sizeof(struct xbsd_disklabel)))
981 fdisk_fatal(unable_to_write);
982#endif
983 sync_disks();
984 return 1;
985}
986
987
988#if !defined (__alpha__)
989static int
990xbsd_translate_fstype(int linux_type)
991{
992 switch (linux_type) {
993 case 0x01: /* DOS 12-bit FAT */
994 case 0x04: /* DOS 16-bit <32M */
995 case 0x06: /* DOS 16-bit >=32M */
996 case 0xe1: /* DOS access */
997 case 0xe3: /* DOS R/O */
998 case 0xf2: /* DOS secondary */
999 return BSD_FS_MSDOS;
1000 case 0x07: /* OS/2 HPFS */
1001 return BSD_FS_HPFS;
1002 default:
1003 return BSD_FS_OTHER;
1004 }
1005}
1006
1007static void
1008xbsd_link_part(void)
1009{
1010 int k, i;
1011 struct partition *p;
1012
1013 k = get_partition(1, partitions);
1014
1015 if (!xbsd_check_new_partition(&i))
1016 return;
1017
1018 p = get_part_table(k);
1019
1020 xbsd_dlabel.d_partitions[i].p_size = get_nr_sects(p);
1021 xbsd_dlabel.d_partitions[i].p_offset = get_start_sect(p);
1022 xbsd_dlabel.d_partitions[i].p_fstype = xbsd_translate_fstype(p->sys_ind);
1023}
1024#endif
1025
1026#if defined (__alpha__)
1027
1028#if !defined(__GLIBC__)
1029typedef unsigned long long uint64_t;
1030#endif
1031
1032static void
1033alpha_bootblock_checksum(char *boot)
1034{
1035 uint64_t *dp, sum;
1036 int i;
1037
1038 dp = (uint64_t *)boot;
1039 sum = 0;
1040 for (i = 0; i < 63; i++)
1041 sum += dp[i];
1042 dp[63] = sum;
1043}
1044#endif /* __alpha__ */
1045
1046#endif /* OSF_LABEL */
diff --git a/util-linux/fdisk_sgi.c b/util-linux/fdisk_sgi.c
new file mode 100644
index 000000000..548a70bdc
--- /dev/null
+++ b/util-linux/fdisk_sgi.c
@@ -0,0 +1,885 @@
1#ifdef CONFIG_FEATURE_SGI_LABEL
2
3/*
4 * Copyright (C) Andreas Neuper, Sep 1998.
5 * This file may be modified and redistributed under
6 * the terms of the GNU Public License.
7 */
8
9struct device_parameter { /* 48 bytes */
10 unsigned char skew;
11 unsigned char gap1;
12 unsigned char gap2;
13 unsigned char sparecyl;
14 unsigned short pcylcount;
15 unsigned short head_vol0;
16 unsigned short ntrks; /* tracks in cyl 0 or vol 0 */
17 unsigned char cmd_tag_queue_depth;
18 unsigned char unused0;
19 unsigned short unused1;
20 unsigned short nsect; /* sectors/tracks in cyl 0 or vol 0 */
21 unsigned short bytes;
22 unsigned short ilfact;
23 unsigned int flags; /* controller flags */
24 unsigned int datarate;
25 unsigned int retries_on_error;
26 unsigned int ms_per_word;
27 unsigned short xylogics_gap1;
28 unsigned short xylogics_syncdelay;
29 unsigned short xylogics_readdelay;
30 unsigned short xylogics_gap2;
31 unsigned short xylogics_readgate;
32 unsigned short xylogics_writecont;
33};
34
35/*
36 * controller flags
37 */
38#define SECTOR_SLIP 0x01
39#define SECTOR_FWD 0x02
40#define TRACK_FWD 0x04
41#define TRACK_MULTIVOL 0x08
42#define IGNORE_ERRORS 0x10
43#define RESEEK 0x20
44#define ENABLE_CMDTAGQ 0x40
45
46typedef struct {
47 unsigned int magic; /* expect SGI_LABEL_MAGIC */
48 unsigned short boot_part; /* active boot partition */
49 unsigned short swap_part; /* active swap partition */
50 unsigned char boot_file[16]; /* name of the bootfile */
51 struct device_parameter devparam; /* 1 * 48 bytes */
52 struct volume_directory { /* 15 * 16 bytes */
53 unsigned char vol_file_name[8]; /* a character array */
54 unsigned int vol_file_start; /* number of logical block */
55 unsigned int vol_file_size; /* number of bytes */
56 } directory[15];
57 struct sgi_partinfo { /* 16 * 12 bytes */
58 unsigned int num_sectors; /* number of blocks */
59 unsigned int start_sector; /* must be cylinder aligned */
60 unsigned int id;
61 } partitions[16];
62 unsigned int csum;
63 unsigned int fillbytes;
64} sgi_partition;
65
66typedef struct {
67 unsigned int magic; /* looks like a magic number */
68 unsigned int a2;
69 unsigned int a3;
70 unsigned int a4;
71 unsigned int b1;
72 unsigned short b2;
73 unsigned short b3;
74 unsigned int c[16];
75 unsigned short d[3];
76 unsigned char scsi_string[50];
77 unsigned char serial[137];
78 unsigned short check1816;
79 unsigned char installer[225];
80} sgiinfo;
81
82#define SGI_LABEL_MAGIC 0x0be5a941
83#define SGI_LABEL_MAGIC_SWAPPED 0x41a9e50b
84#define SGI_INFO_MAGIC 0x00072959
85#define SGI_INFO_MAGIC_SWAPPED 0x59290700
86
87#define SGI_SSWAP16(x) (sgi_other_endian ? __swap16(x) : (uint16_t)(x))
88#define SGI_SSWAP32(x) (sgi_other_endian ? __swap32(x) : (uint32_t)(x))
89
90#define sgilabel ((sgi_partition *)MBRbuffer)
91#define sgiparam (sgilabel->devparam)
92
93/*
94 *
95 * fdisksgilabel.c
96 *
97 * Copyright (C) Andreas Neuper, Sep 1998.
98 * This file may be modified and redistributed under
99 * the terms of the GNU Public License.
100 *
101 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
102 * Internationalization
103 */
104
105
106static int sgi_other_endian;
107static int debug;
108static short sgi_volumes = 1;
109
110/*
111 * only dealing with free blocks here
112 */
113
114typedef struct {
115 unsigned int first;
116 unsigned int last;
117} freeblocks;
118static freeblocks freelist[17]; /* 16 partitions can produce 17 vacant slots */
119
120static void
121setfreelist(int i, unsigned int f, unsigned int l)
122{
123 freelist[i].first = f;
124 freelist[i].last = l;
125}
126
127static void
128add2freelist(unsigned int f, unsigned int l)
129{
130 int i;
131 for (i = 0; i < 17 ; i++)
132 if (freelist[i].last == 0)
133 break;
134 setfreelist(i, f, l);
135}
136
137static void
138clearfreelist(void)
139{
140 int i;
141
142 for (i = 0; i < 17 ; i++)
143 setfreelist(i, 0, 0);
144}
145
146static unsigned int
147isinfreelist(unsigned int b)
148{
149 int i;
150
151 for (i = 0; i < 17 ; i++)
152 if (freelist[i].first <= b && freelist[i].last >= b)
153 return freelist[i].last;
154 return 0;
155}
156 /* return last vacant block of this stride (never 0). */
157 /* the '>=' is not quite correct, but simplifies the code */
158/*
159 * end of free blocks section
160 */
161
162static const struct systypes sgi_sys_types[] = {
163/* SGI_VOLHDR */ { "\x00" "SGI volhdr" },
164/* 0x01 */ { "\x01" "SGI trkrepl" },
165/* 0x02 */ { "\x02" "SGI secrepl" },
166/* SGI_SWAP */ { "\x03" "SGI raw" },
167/* 0x04 */ { "\x04" "SGI bsd" },
168/* 0x05 */ { "\x05" "SGI sysv" },
169/* SGI_ENTIRE_DISK */ { "\x06" "SGI volume" },
170/* SGI_EFS */ { "\x07" "SGI efs" },
171/* 0x08 */ { "\x08" "SGI lvol" },
172/* 0x09 */ { "\x09" "SGI rlvol" },
173/* SGI_XFS */ { "\x0a" "SGI xfs" },
174/* SGI_XFSLOG */ { "\x0b" "SGI xfslog" },
175/* SGI_XLV */ { "\x0c" "SGI xlv" },
176/* SGI_XVM */ { "\x0d" "SGI xvm" },
177/* LINUX_SWAP */ { "\x82" "Linux swap" },
178/* LINUX_NATIVE */ { "\x83" "Linux native" },
179/* LINUX_LVM */ { "\x8d" "Linux LVM" },
180/* LINUX_RAID */ { "\xfd" "Linux RAID" },
181 { NULL }
182};
183
184
185static int
186sgi_get_nsect(void)
187{
188 return SGI_SSWAP16(sgilabel->devparam.nsect);
189}
190
191static int
192sgi_get_ntrks(void)
193{
194 return SGI_SSWAP16(sgilabel->devparam.ntrks);
195}
196
197static unsigned int
198two_s_complement_32bit_sum(unsigned int* base, int size /* in bytes */)
199{
200 int i = 0;
201 unsigned int sum = 0;
202
203 size /= sizeof(unsigned int);
204 for (i = 0; i < size; i++)
205 sum -= SGI_SSWAP32(base[i]);
206 return sum;
207}
208
209static int
210check_sgi_label(void)
211{
212 if (sizeof(sgilabel) > 512) {
213 fprintf(stderr,
214 _("According to MIPS Computer Systems, Inc the "
215 "Label must not contain more than 512 bytes\n"));
216 exit(1);
217 }
218
219 if (sgilabel->magic != SGI_LABEL_MAGIC
220 && sgilabel->magic != SGI_LABEL_MAGIC_SWAPPED) {
221 current_label_type = label_dos;
222 return 0;
223 }
224
225 sgi_other_endian = (sgilabel->magic == SGI_LABEL_MAGIC_SWAPPED);
226 /*
227 * test for correct checksum
228 */
229 if (two_s_complement_32bit_sum((unsigned int*)sgilabel,
230 sizeof(*sgilabel))) {
231 fprintf(stderr,
232 _("Detected sgi disklabel with wrong checksum.\n"));
233 }
234 update_units();
235 current_label_type = label_sgi;
236 partitions = 16;
237 sgi_volumes = 15;
238 return 1;
239}
240
241static unsigned int
242sgi_get_start_sector(int i)
243{
244 return SGI_SSWAP32(sgilabel->partitions[i].start_sector);
245}
246
247static unsigned int
248sgi_get_num_sectors(int i)
249{
250 return SGI_SSWAP32(sgilabel->partitions[i].num_sectors);
251}
252
253static int
254sgi_get_sysid(int i)
255{
256 return SGI_SSWAP32(sgilabel->partitions[i].id);
257}
258
259static int
260sgi_get_bootpartition(void)
261{
262 return SGI_SSWAP16(sgilabel->boot_part);
263}
264
265static int
266sgi_get_swappartition(void)
267{
268 return SGI_SSWAP16(sgilabel->swap_part);
269}
270
271static void
272sgi_list_table(int xtra)
273{
274 int i, w, wd;
275 int kpi = 0; /* kernel partition ID */
276
277 if(xtra) {
278 printf(_("\nDisk %s (SGI disk label): %d heads, %d sectors\n"
279 "%d cylinders, %d physical cylinders\n"
280 "%d extra sects/cyl, interleave %d:1\n"
281 "%s\n"
282 "Units = %s of %d * 512 bytes\n\n"),
283 disk_device, heads, sectors, cylinders,
284 SGI_SSWAP16(sgiparam.pcylcount),
285 SGI_SSWAP16(sgiparam.sparecyl),
286 SGI_SSWAP16(sgiparam.ilfact),
287 (char *)sgilabel,
288 str_units(PLURAL), units_per_sector);
289 } else {
290 printf( _("\nDisk %s (SGI disk label): "
291 "%d heads, %d sectors, %d cylinders\n"
292 "Units = %s of %d * 512 bytes\n\n"),
293 disk_device, heads, sectors, cylinders,
294 str_units(PLURAL), units_per_sector );
295 }
296
297 w = strlen(disk_device);
298 wd = strlen(_("Device"));
299 if (w < wd)
300 w = wd;
301
302 printf(_("----- partitions -----\n"
303 "Pt# %*s Info Start End Sectors Id System\n"),
304 w + 2, _("Device"));
305 for (i = 0 ; i < partitions; i++) {
306 if( sgi_get_num_sectors(i) || debug ) {
307 uint32_t start = sgi_get_start_sector(i);
308 uint32_t len = sgi_get_num_sectors(i);
309 kpi++; /* only count nonempty partitions */
310 printf(
311 "%2d: %s %4s %9ld %9ld %9ld %2x %s\n",
312/* fdisk part number */ i+1,
313/* device */ partname(disk_device, kpi, w+3),
314/* flags */ (sgi_get_swappartition() == i) ? "swap" :
315/* flags */ (sgi_get_bootpartition() == i) ? "boot" : " ",
316/* start */ (long) scround(start),
317/* end */ (long) scround(start+len)-1,
318/* no odd flag on end */(long) len,
319/* type id */ sgi_get_sysid(i),
320/* type name */ partition_type(sgi_get_sysid(i)));
321 }
322 }
323 printf(_("----- Bootinfo -----\nBootfile: %s\n"
324 "----- Directory Entries -----\n"),
325 sgilabel->boot_file);
326 for (i = 0 ; i < sgi_volumes; i++) {
327 if (sgilabel->directory[i].vol_file_size) {
328 uint32_t start = SGI_SSWAP32(sgilabel->directory[i].vol_file_start);
329 uint32_t len = SGI_SSWAP32(sgilabel->directory[i].vol_file_size);
330 unsigned char *name = sgilabel->directory[i].vol_file_name;
331
332 printf(_("%2d: %-10s sector%5u size%8u\n"),
333 i, (char*)name, (unsigned int) start, (unsigned int) len);
334 }
335 }
336}
337
338static void
339sgi_set_bootpartition(int i)
340{
341 sgilabel->boot_part = SGI_SSWAP16(((short)i));
342}
343
344static unsigned int
345sgi_get_lastblock(void)
346{
347 return heads * sectors * cylinders;
348}
349
350static void
351sgi_set_swappartition(int i)
352{
353 sgilabel->swap_part = SGI_SSWAP16(((short)i));
354}
355
356static int
357sgi_check_bootfile(const char* aFile)
358{
359 if (strlen(aFile) < 3) /* "/a\n" is minimum */ {
360 printf(_("\nInvalid Bootfile!\n"
361 "\tThe bootfile must be an absolute non-zero pathname,\n"
362 "\te.g. \"/unix\" or \"/unix.save\".\n"));
363 return 0;
364 } else {
365 if (strlen(aFile) > 16) {
366 printf(_("\n\tName of Bootfile too long: "
367 "16 bytes maximum.\n"));
368 return 0;
369 } else {
370 if (aFile[0] != '/') {
371 printf(_("\n\tBootfile must have a "
372 "fully qualified pathname.\n"));
373 return 0;
374 }
375 }
376 }
377 if (strncmp(aFile, (char*)sgilabel->boot_file, 16)) {
378 printf(_("\n\tBe aware, that the bootfile is not checked for existence.\n\t"
379 "SGI's default is \"/unix\" and for backup \"/unix.save\".\n"));
380 /* filename is correct and did change */
381 return 1;
382 }
383 return 0; /* filename did not change */
384}
385
386static const char *
387sgi_get_bootfile(void)
388{
389 return (char*)sgilabel->boot_file;
390}
391
392static void
393sgi_set_bootfile(const char* aFile)
394{
395 int i = 0;
396
397 if (sgi_check_bootfile(aFile)) {
398 while (i < 16) {
399 if ((aFile[i] != '\n') /* in principle caught again by next line */
400 && (strlen(aFile) > i))
401 sgilabel->boot_file[i] = aFile[i];
402 else
403 sgilabel->boot_file[i] = 0;
404 i++;
405 }
406 printf(_("\n\tBootfile is changed to \"%s\".\n"), sgilabel->boot_file);
407 }
408}
409
410static void
411create_sgiinfo(void)
412{
413 /* I keep SGI's habit to write the sgilabel to the second block */
414 sgilabel->directory[0].vol_file_start = SGI_SSWAP32(2);
415 sgilabel->directory[0].vol_file_size = SGI_SSWAP32(sizeof(sgiinfo));
416 strncpy((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8);
417}
418
419static sgiinfo *fill_sgiinfo(void);
420
421static void
422sgi_write_table(void)
423{
424 sgilabel->csum = 0;
425 sgilabel->csum = SGI_SSWAP32(two_s_complement_32bit_sum(
426 (unsigned int*)sgilabel, sizeof(*sgilabel)));
427 assert(two_s_complement_32bit_sum(
428 (unsigned int*)sgilabel, sizeof(*sgilabel)) == 0);
429
430 if (lseek(fd, 0, SEEK_SET) < 0)
431 fdisk_fatal(unable_to_seek);
432 if (write(fd, sgilabel, SECTOR_SIZE) != SECTOR_SIZE)
433 fdisk_fatal(unable_to_write);
434 if (!strncmp((char*)sgilabel->directory[0].vol_file_name, "sgilabel", 8)) {
435 /*
436 * keep this habit of first writing the "sgilabel".
437 * I never tested whether it works without (AN 981002).
438 */
439 sgiinfo *info = fill_sgiinfo();
440 int infostartblock = SGI_SSWAP32(sgilabel->directory[0].vol_file_start);
441 if (lseek(fd, infostartblock*SECTOR_SIZE, SEEK_SET) < 0)
442 fdisk_fatal(unable_to_seek);
443 if (write(fd, info, SECTOR_SIZE) != SECTOR_SIZE)
444 fdisk_fatal(unable_to_write);
445 free(info);
446 }
447}
448
449static int
450compare_start(int *x, int *y)
451{
452 /*
453 * sort according to start sectors
454 * and prefers largest partition:
455 * entry zero is entire disk entry
456 */
457 unsigned int i = *x;
458 unsigned int j = *y;
459 unsigned int a = sgi_get_start_sector(i);
460 unsigned int b = sgi_get_start_sector(j);
461 unsigned int c = sgi_get_num_sectors(i);
462 unsigned int d = sgi_get_num_sectors(j);
463
464 if (a == b)
465 return (d > c) ? 1 : (d == c) ? 0 : -1;
466 return (a > b) ? 1 : -1;
467}
468
469
470static int
471verify_sgi(int verbose)
472{
473 int Index[16]; /* list of valid partitions */
474 int sortcount = 0; /* number of used partitions, i.e. non-zero lengths */
475 int entire = 0, i = 0;
476 unsigned int start = 0;
477 long long gap = 0; /* count unused blocks */
478 unsigned int lastblock = sgi_get_lastblock();
479
480 clearfreelist();
481 for (i = 0; i < 16; i++) {
482 if (sgi_get_num_sectors(i) != 0) {
483 Index[sortcount++] = i;
484 if (sgi_get_sysid(i) == SGI_ENTIRE_DISK) {
485 if (entire++ == 1) {
486 if (verbose)
487 printf(_("More than one entire disk entry present.\n"));
488 }
489 }
490 }
491 }
492 if (sortcount == 0) {
493 if (verbose)
494 printf(_("No partitions defined\n"));
495 return (lastblock > 0) ? 1 : (lastblock == 0) ? 0 : -1;
496 }
497 qsort(Index, sortcount, sizeof(Index[0]), (void*)compare_start);
498 if (sgi_get_sysid(Index[0]) == SGI_ENTIRE_DISK) {
499 if ((Index[0] != 10) && verbose)
500 printf(_("IRIX likes when Partition 11 covers the entire disk.\n"));
501 if ((sgi_get_start_sector(Index[0]) != 0) && verbose)
502 printf(_("The entire disk partition should start "
503 "at block 0,\n"
504 "not at diskblock %d.\n"),
505 sgi_get_start_sector(Index[0]));
506 if (debug) /* I do not understand how some disks fulfil it */
507 if ((sgi_get_num_sectors(Index[0]) != lastblock) && verbose)
508 printf(_("The entire disk partition is only %d diskblock large,\n"
509 "but the disk is %d diskblocks long.\n"),
510 sgi_get_num_sectors(Index[0]), lastblock);
511 lastblock = sgi_get_num_sectors(Index[0]);
512 } else {
513 if (verbose)
514 printf(_("One Partition (#11) should cover the entire disk.\n"));
515 if (debug > 2)
516 printf("sysid=%d\tpartition=%d\n",
517 sgi_get_sysid(Index[0]), Index[0]+1);
518 }
519 for (i = 1, start = 0; i < sortcount; i++) {
520 int cylsize = sgi_get_nsect() * sgi_get_ntrks();
521
522 if ((sgi_get_start_sector(Index[i]) % cylsize) != 0) {
523 if (debug) /* I do not understand how some disks fulfil it */
524 if (verbose)
525 printf(_("Partition %d does not start on cylinder boundary.\n"),
526 Index[i]+1);
527 }
528 if (sgi_get_num_sectors(Index[i]) % cylsize != 0) {
529 if (debug) /* I do not understand how some disks fulfil it */
530 if (verbose)
531 printf(_("Partition %d does not end on cylinder boundary.\n"),
532 Index[i]+1);
533 }
534 /* We cannot handle several "entire disk" entries. */
535 if (sgi_get_sysid(Index[i]) == SGI_ENTIRE_DISK) continue;
536 if (start > sgi_get_start_sector(Index[i])) {
537 if (verbose)
538 printf(_("The Partition %d and %d overlap by %d sectors.\n"),
539 Index[i-1]+1, Index[i]+1,
540 start - sgi_get_start_sector(Index[i]));
541 if (gap > 0) gap = -gap;
542 if (gap == 0) gap = -1;
543 }
544 if (start < sgi_get_start_sector(Index[i])) {
545 if (verbose)
546 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
547 sgi_get_start_sector(Index[i]) - start,
548 start, sgi_get_start_sector(Index[i])-1);
549 gap += sgi_get_start_sector(Index[i]) - start;
550 add2freelist(start, sgi_get_start_sector(Index[i]));
551 }
552 start = sgi_get_start_sector(Index[i])
553 + sgi_get_num_sectors(Index[i]);
554 if (debug > 1) {
555 if (verbose)
556 printf("%2d:%12d\t%12d\t%12d\n", Index[i],
557 sgi_get_start_sector(Index[i]),
558 sgi_get_num_sectors(Index[i]),
559 sgi_get_sysid(Index[i]));
560 }
561 }
562 if (start < lastblock) {
563 if (verbose)
564 printf(_("Unused gap of %8u sectors - sectors %8u-%u\n"),
565 lastblock - start, start, lastblock-1);
566 gap += lastblock - start;
567 add2freelist(start, lastblock);
568 }
569 /*
570 * Done with arithmetics
571 * Go for details now
572 */
573 if (verbose) {
574 if (!sgi_get_num_sectors(sgi_get_bootpartition())) {
575 printf(_("\nThe boot partition does not exist.\n"));
576 }
577 if (!sgi_get_num_sectors(sgi_get_swappartition())) {
578 printf(_("\nThe swap partition does not exist.\n"));
579 } else {
580 if ((sgi_get_sysid(sgi_get_swappartition()) != SGI_SWAP)
581 && (sgi_get_sysid(sgi_get_swappartition()) != LINUX_SWAP))
582 printf(_("\nThe swap partition has no swap type.\n"));
583 }
584 if (sgi_check_bootfile("/unix"))
585 printf(_("\tYou have chosen an unusual boot file name.\n"));
586 }
587 return (gap > 0) ? 1 : (gap == 0) ? 0 : -1;
588}
589
590static int
591sgi_gaps(void)
592{
593 /*
594 * returned value is:
595 * = 0 : disk is properly filled to the rim
596 * < 0 : there is an overlap
597 * > 0 : there is still some vacant space
598 */
599 return verify_sgi(0);
600}
601
602static void
603sgi_change_sysid(int i, int sys)
604{
605 if( sgi_get_num_sectors(i) == 0 ) { /* caught already before, ... */
606 printf(_("Sorry You may change the Tag of non-empty partitions.\n"));
607 return;
608 }
609 if (((sys != SGI_ENTIRE_DISK) && (sys != SGI_VOLHDR))
610 && (sgi_get_start_sector(i) < 1) ) {
611 read_maybe_empty(
612 _("It is highly recommended that the partition at offset 0\n"
613 "is of type \"SGI volhdr\", the IRIX system will rely on it to\n"
614 "retrieve from its directory standalone tools like sash and fx.\n"
615 "Only the \"SGI volume\" entire disk section may violate this.\n"
616 "Type YES if you are sure about tagging this partition differently.\n"));
617 if (strcmp(line_ptr, _("YES\n")))
618 return;
619 }
620 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
621}
622
623/* returns partition index of first entry marked as entire disk */
624static int
625sgi_entire(void)
626{
627 int i;
628
629 for (i = 0; i < 16; i++)
630 if (sgi_get_sysid(i) == SGI_VOLUME)
631 return i;
632 return -1;
633}
634
635static void
636sgi_set_partition(int i, unsigned int start, unsigned int length, int sys)
637{
638 sgilabel->partitions[i].id = SGI_SSWAP32(sys);
639 sgilabel->partitions[i].num_sectors = SGI_SSWAP32(length);
640 sgilabel->partitions[i].start_sector = SGI_SSWAP32(start);
641 set_changed(i);
642 if (sgi_gaps() < 0) /* rebuild freelist */
643 printf(_("Do You know, You got a partition overlap on the disk?\n"));
644}
645
646static void
647sgi_set_entire(void)
648{
649 int n;
650
651 for (n = 10; n < partitions; n++) {
652 if(!sgi_get_num_sectors(n) ) {
653 sgi_set_partition(n, 0, sgi_get_lastblock(), SGI_VOLUME);
654 break;
655 }
656 }
657}
658
659static void
660sgi_set_volhdr(void)
661{
662 int n;
663
664 for (n = 8; n < partitions; n++) {
665 if (!sgi_get_num_sectors(n)) {
666 /*
667 * 5 cylinders is an arbitrary value I like
668 * IRIX 5.3 stored files in the volume header
669 * (like sash, symmon, fx, ide) with ca. 3200
670 * sectors.
671 */
672 if (heads * sectors * 5 < sgi_get_lastblock())
673 sgi_set_partition(n, 0, heads * sectors * 5, SGI_VOLHDR);
674 break;
675 }
676 }
677}
678
679static void
680sgi_delete_partition(int i)
681{
682 sgi_set_partition(i, 0, 0, 0);
683}
684
685static void
686sgi_add_partition(int n, int sys)
687{
688 char mesg[256];
689 unsigned int first = 0, last = 0;
690
691 if (n == 10) {
692 sys = SGI_VOLUME;
693 } else if (n == 8) {
694 sys = 0;
695 }
696 if(sgi_get_num_sectors(n)) {
697 printf(_("Partition %d is already defined. Delete "
698 "it before re-adding it.\n"), n + 1);
699 return;
700 }
701 if ((sgi_entire() == -1) && (sys != SGI_VOLUME)) {
702 printf(_("Attempting to generate entire disk entry automatically.\n"));
703 sgi_set_entire();
704 sgi_set_volhdr();
705 }
706 if ((sgi_gaps() == 0) && (sys != SGI_VOLUME)) {
707 printf(_("The entire disk is already covered with partitions.\n"));
708 return;
709 }
710 if (sgi_gaps() < 0) {
711 printf(_("You got a partition overlap on the disk. Fix it first!\n"));
712 return;
713 }
714 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
715 while (1) {
716 if(sys == SGI_VOLUME) {
717 last = sgi_get_lastblock();
718 first = read_int(0, 0, last-1, 0, mesg);
719 if (first != 0) {
720 printf(_("It is highly recommended that eleventh partition\n"
721 "covers the entire disk and is of type 'SGI volume'\n"));
722 }
723 } else {
724 first = freelist[0].first;
725 last = freelist[0].last;
726 first = read_int(scround(first), scround(first), scround(last)-1,
727 0, mesg);
728 }
729 if (display_in_cyl_units)
730 first *= units_per_sector;
731 else
732 first = first; /* align to cylinder if you know how ... */
733 if(!last )
734 last = isinfreelist(first);
735 if(last == 0) {
736 printf(_("You will get a partition overlap on the disk. "
737 "Fix it first!\n"));
738 } else
739 break;
740 }
741 snprintf(mesg, sizeof(mesg), _(" Last %s"), str_units(SINGULAR));
742 last = read_int(scround(first), scround(last)-1, scround(last)-1,
743 scround(first), mesg)+1;
744 if (display_in_cyl_units)
745 last *= units_per_sector;
746 else
747 last = last; /* align to cylinder if You know how ... */
748 if ( (sys == SGI_VOLUME) && (first != 0 || last != sgi_get_lastblock() ) )
749 printf(_("It is highly recommended that eleventh partition\n"
750 "covers the entire disk and is of type 'SGI volume'\n"));
751 sgi_set_partition(n, first, last-first, sys);
752}
753
754#ifdef CONFIG_FEATURE_FDISK_ADVANCED
755static void
756create_sgilabel(void)
757{
758 struct hd_geometry geometry;
759 struct {
760 unsigned int start;
761 unsigned int nsect;
762 int sysid;
763 } old[4];
764 int i = 0;
765 long longsectors; /* the number of sectors on the device */
766 int res; /* the result from the ioctl */
767 int sec_fac; /* the sector factor */
768
769 sec_fac = sector_size / 512; /* determine the sector factor */
770
771 fprintf( stderr,
772 _("Building a new SGI disklabel. Changes will remain in memory only,\n"
773 "until you decide to write them. After that, of course, the previous\n"
774 "content will be unrecoverably lost.\n\n"));
775
776 sgi_other_endian = (BYTE_ORDER == LITTLE_ENDIAN);
777 res = ioctl(fd, BLKGETSIZE, &longsectors);
778 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
779 heads = geometry.heads;
780 sectors = geometry.sectors;
781 if (res == 0) {
782 /* the get device size ioctl was successful */
783 cylinders = longsectors / (heads * sectors);
784 cylinders /= sec_fac;
785 } else {
786 /* otherwise print error and use truncated version */
787 cylinders = geometry.cylinders;
788 fprintf(stderr,
789 _("Warning: BLKGETSIZE ioctl failed on %s. "
790 "Using geometry cylinder value of %d.\n"
791 "This value may be truncated for devices"
792 " > 33.8 GB.\n"), disk_device, cylinders);
793 }
794 }
795 for (i = 0; i < 4; i++) {
796 old[i].sysid = 0;
797 if (valid_part_table_flag(MBRbuffer)) {
798 if(get_part_table(i)->sys_ind) {
799 old[i].sysid = get_part_table(i)->sys_ind;
800 old[i].start = get_start_sect(get_part_table(i));
801 old[i].nsect = get_nr_sects(get_part_table(i));
802 printf(_("Trying to keep parameters of partition %d.\n"), i);
803 if (debug)
804 printf(_("ID=%02x\tSTART=%d\tLENGTH=%d\n"),
805 old[i].sysid, old[i].start, old[i].nsect);
806 }
807 }
808 }
809
810 memset(MBRbuffer, 0, sizeof(MBRbuffer));
811 sgilabel->magic = SGI_SSWAP32(SGI_LABEL_MAGIC);
812 sgilabel->boot_part = SGI_SSWAP16(0);
813 sgilabel->swap_part = SGI_SSWAP16(1);
814
815 /* sizeof(sgilabel->boot_file) = 16 > 6 */
816 memset(sgilabel->boot_file, 0, 16);
817 strcpy((char*)sgilabel->boot_file, "/unix");
818
819 sgilabel->devparam.skew = (0);
820 sgilabel->devparam.gap1 = (0);
821 sgilabel->devparam.gap2 = (0);
822 sgilabel->devparam.sparecyl = (0);
823 sgilabel->devparam.pcylcount = SGI_SSWAP16(geometry.cylinders);
824 sgilabel->devparam.head_vol0 = SGI_SSWAP16(0);
825 sgilabel->devparam.ntrks = SGI_SSWAP16(geometry.heads);
826 /* tracks/cylinder (heads) */
827 sgilabel->devparam.cmd_tag_queue_depth = (0);
828 sgilabel->devparam.unused0 = (0);
829 sgilabel->devparam.unused1 = SGI_SSWAP16(0);
830 sgilabel->devparam.nsect = SGI_SSWAP16(geometry.sectors);
831 /* sectors/track */
832 sgilabel->devparam.bytes = SGI_SSWAP16(512);
833 sgilabel->devparam.ilfact = SGI_SSWAP16(1);
834 sgilabel->devparam.flags = SGI_SSWAP32(TRACK_FWD|
835 IGNORE_ERRORS|RESEEK);
836 sgilabel->devparam.datarate = SGI_SSWAP32(0);
837 sgilabel->devparam.retries_on_error = SGI_SSWAP32(1);
838 sgilabel->devparam.ms_per_word = SGI_SSWAP32(0);
839 sgilabel->devparam.xylogics_gap1 = SGI_SSWAP16(0);
840 sgilabel->devparam.xylogics_syncdelay = SGI_SSWAP16(0);
841 sgilabel->devparam.xylogics_readdelay = SGI_SSWAP16(0);
842 sgilabel->devparam.xylogics_gap2 = SGI_SSWAP16(0);
843 sgilabel->devparam.xylogics_readgate = SGI_SSWAP16(0);
844 sgilabel->devparam.xylogics_writecont = SGI_SSWAP16(0);
845 memset( &(sgilabel->directory), 0, sizeof(struct volume_directory)*15 );
846 memset( &(sgilabel->partitions), 0, sizeof(struct sgi_partinfo)*16 );
847 current_label_type = label_sgi;
848 partitions = 16;
849 sgi_volumes = 15;
850 sgi_set_entire();
851 sgi_set_volhdr();
852 for (i = 0; i < 4; i++) {
853 if(old[i].sysid) {
854 sgi_set_partition(i, old[i].start, old[i].nsect, old[i].sysid);
855 }
856 }
857}
858
859static void
860sgi_set_xcyl(void)
861{
862 /* do nothing in the beginning */
863}
864#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
865
866/* _____________________________________________________________
867 */
868
869static sgiinfo *
870fill_sgiinfo(void)
871{
872 sgiinfo *info = calloc(1, sizeof(sgiinfo));
873
874 info->magic = SGI_SSWAP32(SGI_INFO_MAGIC);
875 info->b1 = SGI_SSWAP32(-1);
876 info->b2 = SGI_SSWAP16(-1);
877 info->b3 = SGI_SSWAP16(1);
878 /* You may want to replace this string !!!!!!! */
879 strcpy( (char*)info->scsi_string, "IBM OEM 0662S12 3 30" );
880 strcpy( (char*)info->serial, "0000" );
881 info->check1816 = SGI_SSWAP16(18*256 +16 );
882 strcpy( (char*)info->installer, "Sfx version 5.3, Oct 18, 1994" );
883 return info;
884}
885#endif /* SGI_LABEL */
diff --git a/util-linux/fdisk_sun.c b/util-linux/fdisk_sun.c
new file mode 100644
index 000000000..1e8f2e525
--- /dev/null
+++ b/util-linux/fdisk_sun.c
@@ -0,0 +1,729 @@
1#ifdef CONFIG_FEATURE_SUN_LABEL
2
3#define SUN_LABEL_MAGIC 0xDABE
4#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA
5#define SUN_SSWAP16(x) (sun_other_endian ? __swap16(x) : (uint16_t)(x))
6#define SUN_SSWAP32(x) (sun_other_endian ? __swap32(x) : (uint32_t)(x))
7
8/* Copied from linux/major.h */
9#define FLOPPY_MAJOR 2
10
11#define SCSI_IOCTL_GET_IDLUN 0x5382
12
13/*
14 * fdisksunlabel.c
15 *
16 * I think this is mostly, or entirely, due to
17 * Jakub Jelinek (jj@sunsite.mff.cuni.cz), July 1996
18 *
19 * Merged with fdisk for other architectures, aeb, June 1998.
20 *
21 * Sat Mar 20 EST 1999 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
22 * Internationalization
23 */
24
25
26static int sun_other_endian;
27static int scsi_disk;
28static int floppy;
29
30#ifndef IDE0_MAJOR
31#define IDE0_MAJOR 3
32#endif
33#ifndef IDE1_MAJOR
34#define IDE1_MAJOR 22
35#endif
36
37static void
38guess_device_type(void)
39{
40 struct stat bootstat;
41
42 if (fstat(fd, &bootstat) < 0) {
43 scsi_disk = 0;
44 floppy = 0;
45 } else if (S_ISBLK(bootstat.st_mode)
46 && (major(bootstat.st_rdev) == IDE0_MAJOR ||
47 major(bootstat.st_rdev) == IDE1_MAJOR)) {
48 scsi_disk = 0;
49 floppy = 0;
50 } else if (S_ISBLK(bootstat.st_mode)
51 && major(bootstat.st_rdev) == FLOPPY_MAJOR) {
52 scsi_disk = 0;
53 floppy = 1;
54 } else {
55 scsi_disk = 1;
56 floppy = 0;
57 }
58}
59
60static const struct systypes sun_sys_types[] = {
61 { "\x00" "Empty" }, /* 0 */
62 { "\x01" "Boot" }, /* 1 */
63 { "\x02" "SunOS root" }, /* 2 */
64 { "\x03" "SunOS swap" }, /* SUNOS_SWAP */
65 { "\x04" "SunOS usr" }, /* 4 */
66 { "\x05" "Whole disk" }, /* SUN_WHOLE_DISK */
67 { "\x06" "SunOS stand" }, /* 6 */
68 { "\x07" "SunOS var" }, /* 7 */
69 { "\x08" "SunOS home" }, /* 8 */
70 { "\x82" "Linux swap" }, /* LINUX_SWAP */
71 { "\x83" "Linux native" }, /* LINUX_NATIVE */
72 { "\x8e" "Linux LVM" }, /* 0x8e */
73/* New (2.2.x) raid partition with autodetect using persistent superblock */
74 { "\xfd" "Linux raid autodetect" }, /* 0xfd */
75 { NULL }
76};
77
78
79static void
80set_sun_partition(int i, uint start, uint stop, int sysid)
81{
82 sunlabel->infos[i].id = sysid;
83 sunlabel->partitions[i].start_cylinder =
84 SUN_SSWAP32(start / (heads * sectors));
85 sunlabel->partitions[i].num_sectors =
86 SUN_SSWAP32(stop - start);
87 set_changed(i);
88}
89
90static int
91check_sun_label(void)
92{
93 unsigned short *ush;
94 int csum;
95
96 if (sunlabel->magic != SUN_LABEL_MAGIC
97 && sunlabel->magic != SUN_LABEL_MAGIC_SWAPPED) {
98 current_label_type = label_dos;
99 sun_other_endian = 0;
100 return 0;
101 }
102 sun_other_endian = (sunlabel->magic == SUN_LABEL_MAGIC_SWAPPED);
103 ush = ((unsigned short *) (sunlabel + 1)) - 1;
104 for (csum = 0; ush >= (unsigned short *)sunlabel;) csum ^= *ush--;
105 if (csum) {
106 fprintf(stderr,_("Detected sun disklabel with wrong checksum.\n"
107 "Probably you'll have to set all the values,\n"
108 "e.g. heads, sectors, cylinders and partitions\n"
109 "or force a fresh label (s command in main menu)\n"));
110 } else {
111 heads = SUN_SSWAP16(sunlabel->ntrks);
112 cylinders = SUN_SSWAP16(sunlabel->ncyl);
113 sectors = SUN_SSWAP16(sunlabel->nsect);
114 }
115 update_units();
116 current_label_type = label_sun;
117 partitions = 8;
118 return 1;
119}
120
121static const struct sun_predefined_drives {
122 const char *vendor;
123 const char *model;
124 unsigned short sparecyl;
125 unsigned short ncyl;
126 unsigned short nacyl;
127 unsigned short pcylcount;
128 unsigned short ntrks;
129 unsigned short nsect;
130 unsigned short rspeed;
131} sun_drives[] = {
132 { "Quantum","ProDrive 80S",1,832,2,834,6,34,3662},
133 { "Quantum","ProDrive 105S",1,974,2,1019,6,35,3662},
134 { "CDC","Wren IV 94171-344",3,1545,2,1549,9,46,3600},
135 { "IBM","DPES-31080",0,4901,2,4903,4,108,5400},
136 { "IBM","DORS-32160",0,1015,2,1017,67,62,5400},
137 { "IBM","DNES-318350",0,11199,2,11474,10,320,7200},
138 { "SEAGATE","ST34371",0,3880,2,3882,16,135,7228},
139 { "","SUN0104",1,974,2,1019,6,35,3662},
140 { "","SUN0207",4,1254,2,1272,9,36,3600},
141 { "","SUN0327",3,1545,2,1549,9,46,3600},
142 { "","SUN0340",0,1538,2,1544,6,72,4200},
143 { "","SUN0424",2,1151,2,2500,9,80,4400},
144 { "","SUN0535",0,1866,2,2500,7,80,5400},
145 { "","SUN0669",5,1614,2,1632,15,54,3600},
146 { "","SUN1.0G",5,1703,2,1931,15,80,3597},
147 { "","SUN1.05",0,2036,2,2038,14,72,5400},
148 { "","SUN1.3G",6,1965,2,3500,17,80,5400},
149 { "","SUN2.1G",0,2733,2,3500,19,80,5400},
150 { "IOMEGA","Jaz",0,1019,2,1021,64,32,5394},
151};
152
153static const struct sun_predefined_drives *
154sun_autoconfigure_scsi(void)
155{
156 const struct sun_predefined_drives *p = NULL;
157
158#ifdef SCSI_IOCTL_GET_IDLUN
159 unsigned int id[2];
160 char buffer[2048];
161 char buffer2[2048];
162 FILE *pfd;
163 char *vendor;
164 char *model;
165 char *q;
166 int i;
167
168 if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, &id))
169 return NULL;
170
171 sprintf(buffer,
172 "Host: scsi%d Channel: %02d Id: %02d Lun: %02d\n",
173 /* This is very wrong (works only if you have one HBA),
174 but I haven't found a way how to get hostno
175 from the current kernel */
176 0,
177 (id[0]>>16) & 0xff,
178 id[0] & 0xff,
179 (id[0]>>8) & 0xff
180 );
181 pfd = fopen("/proc/scsi/scsi", "r");
182 if (!pfd) {
183 return NULL;
184 }
185 while (fgets(buffer2, 2048, pfd)) {
186 if (strcmp(buffer, buffer2))
187 continue;
188 if (!fgets(buffer2, 2048, pfd))
189 break;
190 q = strstr(buffer2, "Vendor: ");
191 if (!q)
192 break;
193 q += 8;
194 vendor = q;
195 q = strstr(q, " ");
196 *q++ = '\0'; /* truncate vendor name */
197 q = strstr(q, "Model: ");
198 if (!q)
199 break;
200 *q = '\0';
201 q += 7;
202 model = q;
203 q = strstr(q, " Rev: ");
204 if (!q)
205 break;
206 *q = '\0';
207 for (i = 0; i < SIZE(sun_drives); i++) {
208 if (*sun_drives[i].vendor && strcasecmp(sun_drives[i].vendor, vendor))
209 continue;
210 if (!strstr(model, sun_drives[i].model))
211 continue;
212 printf(_("Autoconfigure found a %s%s%s\n"),
213 sun_drives[i].vendor,
214 (*sun_drives[i].vendor) ? " " : "",
215 sun_drives[i].model);
216 p = sun_drives + i;
217 break;
218 }
219 break;
220 }
221 fclose(pfd);
222#endif
223 return p;
224}
225
226static void
227create_sunlabel(void)
228{
229 struct hd_geometry geometry;
230 unsigned int ndiv;
231 int i;
232 unsigned char c;
233 const struct sun_predefined_drives *p = NULL;
234
235 fprintf(stderr,
236 _("Building a new sun disklabel. Changes will remain in memory only,\n"
237 "until you decide to write them. After that, of course, the previous\n"
238 "content won't be recoverable.\n\n"));
239 sun_other_endian = BB_LITTLE_ENDIAN;
240 memset(MBRbuffer, 0, sizeof(MBRbuffer));
241 sunlabel->magic = SUN_SSWAP16(SUN_LABEL_MAGIC);
242 if (!floppy) {
243 puts(_("Drive type\n"
244 " ? auto configure\n"
245 " 0 custom (with hardware detected defaults)"));
246 for (i = 0; i < SIZE(sun_drives); i++) {
247 printf(" %c %s%s%s\n",
248 i + 'a', sun_drives[i].vendor,
249 (*sun_drives[i].vendor) ? " " : "",
250 sun_drives[i].model);
251 }
252 while (1) {
253 c = read_nonempty(_("Select type (? for auto, 0 for custom): "));
254 if (c >= 'a' && c < 'a' + SIZE(sun_drives)) {
255 p = sun_drives + c - 'a';
256 break;
257 } else if (c >= 'A' && c < 'A' + SIZE(sun_drives)) {
258 p = sun_drives + c - 'A';
259 break;
260 } else if (c == '0') {
261 break;
262 } else if (c == '?' && scsi_disk) {
263 p = sun_autoconfigure_scsi();
264 if (!p)
265 printf(_("Autoconfigure failed.\n"));
266 else
267 break;
268 }
269 }
270 }
271 if (!p || floppy) {
272 if (!ioctl(fd, HDIO_GETGEO, &geometry)) {
273 heads = geometry.heads;
274 sectors = geometry.sectors;
275 cylinders = geometry.cylinders;
276 } else {
277 heads = 0;
278 sectors = 0;
279 cylinders = 0;
280 }
281 if (floppy) {
282 sunlabel->nacyl = 0;
283 sunlabel->pcylcount = SUN_SSWAP16(cylinders);
284 sunlabel->rspeed = SUN_SSWAP16(300);
285 sunlabel->ilfact = SUN_SSWAP16(1);
286 sunlabel->sparecyl = 0;
287 } else {
288 heads = read_int(1,heads,1024,0,_("Heads"));
289 sectors = read_int(1,sectors,1024,0,_("Sectors/track"));
290 if (cylinders)
291 cylinders = read_int(1,cylinders-2,65535,0,_("Cylinders"));
292 else
293 cylinders = read_int(1,0,65535,0,_("Cylinders"));
294 sunlabel->nacyl = SUN_SSWAP16(read_int(0,2,65535,0, _("Alternate cylinders")));
295 sunlabel->pcylcount = SUN_SSWAP16(read_int(0,cylinders+SUN_SSWAP16(sunlabel->nacyl), 65535,0, _("Physical cylinders")));
296 sunlabel->rspeed = SUN_SSWAP16(read_int(1,5400,100000,0, _("Rotation speed (rpm)")));
297 sunlabel->ilfact = SUN_SSWAP16(read_int(1,1,32,0, _("Interleave factor")));
298 sunlabel->sparecyl = SUN_SSWAP16(read_int(0,0,sectors,0, _("Extra sectors per cylinder")));
299 }
300 } else {
301 sunlabel->sparecyl = SUN_SSWAP16(p->sparecyl);
302 sunlabel->ncyl = SUN_SSWAP16(p->ncyl);
303 sunlabel->nacyl = SUN_SSWAP16(p->nacyl);
304 sunlabel->pcylcount = SUN_SSWAP16(p->pcylcount);
305 sunlabel->ntrks = SUN_SSWAP16(p->ntrks);
306 sunlabel->nsect = SUN_SSWAP16(p->nsect);
307 sunlabel->rspeed = SUN_SSWAP16(p->rspeed);
308 sunlabel->ilfact = SUN_SSWAP16(1);
309 cylinders = p->ncyl;
310 heads = p->ntrks;
311 sectors = p->nsect;
312 puts(_("You may change all the disk params from the x menu"));
313 }
314
315 snprintf((char *)(sunlabel->info), sizeof(sunlabel->info),
316 "%s%s%s cyl %d alt %d hd %d sec %d",
317 p ? p->vendor : "", (p && *p->vendor) ? " " : "",
318 p ? p->model : (floppy ? _("3,5\" floppy") : _("Linux custom")),
319 cylinders, SUN_SSWAP16(sunlabel->nacyl), heads, sectors);
320
321 sunlabel->ntrks = SUN_SSWAP16(heads);
322 sunlabel->nsect = SUN_SSWAP16(sectors);
323 sunlabel->ncyl = SUN_SSWAP16(cylinders);
324 if (floppy)
325 set_sun_partition(0, 0, cylinders * heads * sectors, LINUX_NATIVE);
326 else {
327 if (cylinders * heads * sectors >= 150 * 2048) {
328 ndiv = cylinders - (50 * 2048 / (heads * sectors)); /* 50M swap */
329 } else
330 ndiv = cylinders * 2 / 3;
331 set_sun_partition(0, 0, ndiv * heads * sectors, LINUX_NATIVE);
332 set_sun_partition(1, ndiv * heads * sectors, cylinders * heads * sectors, LINUX_SWAP);
333 sunlabel->infos[1].flags |= 0x01; /* Not mountable */
334 }
335 set_sun_partition(2, 0, cylinders * heads * sectors, SUN_WHOLE_DISK);
336 {
337 unsigned short *ush = (unsigned short *)sunlabel;
338 unsigned short csum = 0;
339 while (ush < (unsigned short *)(&sunlabel->csum))
340 csum ^= *ush++;
341 sunlabel->csum = csum;
342 }
343
344 set_all_unchanged();
345 set_changed(0);
346 get_boot(create_empty_sun);
347}
348
349static void
350toggle_sunflags(int i, unsigned char mask)
351{
352 if (sunlabel->infos[i].flags & mask)
353 sunlabel->infos[i].flags &= ~mask;
354 else
355 sunlabel->infos[i].flags |= mask;
356 set_changed(i);
357}
358
359static void
360fetch_sun(uint *starts, uint *lens, uint *start, uint *stop)
361{
362 int i, continuous = 1;
363
364 *start = 0;
365 *stop = cylinders * heads * sectors;
366 for (i = 0; i < partitions; i++) {
367 if (sunlabel->partitions[i].num_sectors
368 && sunlabel->infos[i].id
369 && sunlabel->infos[i].id != SUN_WHOLE_DISK) {
370 starts[i] = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
371 lens[i] = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
372 if (continuous) {
373 if (starts[i] == *start)
374 *start += lens[i];
375 else if (starts[i] + lens[i] >= *stop)
376 *stop = starts[i];
377 else
378 continuous = 0;
379 /* There will be probably more gaps
380 than one, so lets check afterwards */
381 }
382 } else {
383 starts[i] = 0;
384 lens[i] = 0;
385 }
386 }
387}
388
389static uint *verify_sun_starts;
390
391static int
392verify_sun_cmp(int *a, int *b)
393{
394 if (*a == -1) return 1;
395 if (*b == -1) return -1;
396 if (verify_sun_starts[*a] > verify_sun_starts[*b]) return 1;
397 return -1;
398}
399
400static void
401verify_sun(void)
402{
403 uint starts[8], lens[8], start, stop;
404 int i,j,k,starto,endo;
405 int array[8];
406
407 verify_sun_starts = starts;
408 fetch_sun(starts,lens,&start,&stop);
409 for (k = 0; k < 7; k++) {
410 for (i = 0; i < 8; i++) {
411 if (k && (lens[i] % (heads * sectors))) {
412 printf(_("Partition %d doesn't end on cylinder boundary\n"), i+1);
413 }
414 if (lens[i]) {
415 for (j = 0; j < i; j++)
416 if (lens[j]) {
417 if (starts[j] == starts[i]+lens[i]) {
418 starts[j] = starts[i]; lens[j] += lens[i];
419 lens[i] = 0;
420 } else if (starts[i] == starts[j]+lens[j]){
421 lens[j] += lens[i];
422 lens[i] = 0;
423 } else if (!k) {
424 if (starts[i] < starts[j]+lens[j]
425 && starts[j] < starts[i]+lens[i]) {
426 starto = starts[i];
427 if (starts[j] > starto)
428 starto = starts[j];
429 endo = starts[i]+lens[i];
430 if (starts[j]+lens[j] < endo)
431 endo = starts[j]+lens[j];
432 printf(_("Partition %d overlaps with others in "
433 "sectors %d-%d\n"), i+1, starto, endo);
434 }
435 }
436 }
437 }
438 }
439 }
440 for (i = 0; i < 8; i++) {
441 if (lens[i])
442 array[i] = i;
443 else
444 array[i] = -1;
445 }
446 qsort(array,SIZE(array),sizeof(array[0]),
447 (int (*)(const void *,const void *)) verify_sun_cmp);
448 if (array[0] == -1) {
449 printf(_("No partitions defined\n"));
450 return;
451 }
452 stop = cylinders * heads * sectors;
453 if (starts[array[0]])
454 printf(_("Unused gap - sectors 0-%d\n"),starts[array[0]]);
455 for (i = 0; i < 7 && array[i+1] != -1; i++) {
456 printf(_("Unused gap - sectors %d-%d\n"),starts[array[i]]+lens[array[i]],starts[array[i+1]]);
457 }
458 start = starts[array[i]] + lens[array[i]];
459 if (start < stop)
460 printf(_("Unused gap - sectors %d-%d\n"),start,stop);
461}
462
463static void
464add_sun_partition(int n, int sys)
465{
466 uint start, stop, stop2;
467 uint starts[8], lens[8];
468 int whole_disk = 0;
469
470 char mesg[256];
471 int i, first, last;
472
473 if (sunlabel->partitions[n].num_sectors && sunlabel->infos[n].id) {
474 printf(_("Partition %d is already defined. Delete "
475 "it before re-adding it.\n"), n + 1);
476 return;
477 }
478
479 fetch_sun(starts,lens,&start,&stop);
480 if (stop <= start) {
481 if (n == 2)
482 whole_disk = 1;
483 else {
484 printf(_("Other partitions already cover the whole disk.\nDelete "
485 "some/shrink them before retry.\n"));
486 return;
487 }
488 }
489 snprintf(mesg, sizeof(mesg), _("First %s"), str_units(SINGULAR));
490 while (1) {
491 if (whole_disk)
492 first = read_int(0, 0, 0, 0, mesg);
493 else
494 first = read_int(scround(start), scround(stop)+1,
495 scround(stop), 0, mesg);
496 if (display_in_cyl_units)
497 first *= units_per_sector;
498 else
499 /* Starting sector has to be properly aligned */
500 first = (first + heads * sectors - 1) / (heads * sectors);
501 if (n == 2 && first != 0)
502 printf("\
503It is highly recommended that the third partition covers the whole disk\n\
504and is of type `Whole disk'\n");
505 /* ewt asks to add: "don't start a partition at cyl 0"
506 However, edmundo@rano.demon.co.uk writes:
507 "In addition to having a Sun partition table, to be able to
508 boot from the disc, the first partition, /dev/sdX1, must
509 start at cylinder 0. This means that /dev/sdX1 contains
510 the partition table and the boot block, as these are the
511 first two sectors of the disc. Therefore you must be
512 careful what you use /dev/sdX1 for. In particular, you must
513 not use a partition starting at cylinder 0 for Linux swap,
514 as that would overwrite the partition table and the boot
515 block. You may, however, use such a partition for a UFS
516 or EXT2 file system, as these file systems leave the first
517 1024 bytes undisturbed. */
518 /* On the other hand, one should not use partitions
519 starting at block 0 in an md, or the label will
520 be trashed. */
521 for (i = 0; i < partitions; i++)
522 if (lens[i] && starts[i] <= first && starts[i] + lens[i] > first)
523 break;
524 if (i < partitions && !whole_disk) {
525 if (n == 2 && !first) {
526 whole_disk = 1;
527 break;
528 }
529 printf(_("Sector %d is already allocated\n"), first);
530 } else
531 break;
532 }
533 stop = cylinders * heads * sectors;
534 stop2 = stop;
535 for (i = 0; i < partitions; i++) {
536 if (starts[i] > first && starts[i] < stop)
537 stop = starts[i];
538 }
539 snprintf(mesg, sizeof(mesg),
540 _("Last %s or +size or +sizeM or +sizeK"),
541 str_units(SINGULAR));
542 if (whole_disk)
543 last = read_int(scround(stop2), scround(stop2), scround(stop2),
544 0, mesg);
545 else if (n == 2 && !first)
546 last = read_int(scround(first), scround(stop2), scround(stop2),
547 scround(first), mesg);
548 else
549 last = read_int(scround(first), scround(stop), scround(stop),
550 scround(first), mesg);
551 if (display_in_cyl_units)
552 last *= units_per_sector;
553 if (n == 2 && !first) {
554 if (last >= stop2) {
555 whole_disk = 1;
556 last = stop2;
557 } else if (last > stop) {
558 printf(_("You haven't covered the whole disk with "
559 "the 3rd partition, but your value\n"
560 "%d %s covers some other partition. "
561 "Your entry has been changed\n"
562 "to %d %s\n"),
563 scround(last), str_units(SINGULAR),
564 scround(stop), str_units(SINGULAR));
565 last = stop;
566 }
567 } else if (!whole_disk && last > stop)
568 last = stop;
569
570 if (whole_disk)
571 sys = SUN_WHOLE_DISK;
572 set_sun_partition(n, first, last, sys);
573}
574
575static void
576sun_delete_partition(int i)
577{
578 unsigned int nsec;
579
580 if (i == 2
581 && sunlabel->infos[i].id == SUN_WHOLE_DISK
582 && !sunlabel->partitions[i].start_cylinder
583 && (nsec = SUN_SSWAP32(sunlabel->partitions[i].num_sectors)) == heads * sectors * cylinders)
584 printf(_("If you want to maintain SunOS/Solaris compatibility, "
585 "consider leaving this\n"
586 "partition as Whole disk (5), starting at 0, with %u "
587 "sectors\n"), nsec);
588 sunlabel->infos[i].id = 0;
589 sunlabel->partitions[i].num_sectors = 0;
590}
591
592static void
593sun_change_sysid(int i, int sys)
594{
595 if (sys == LINUX_SWAP && !sunlabel->partitions[i].start_cylinder) {
596 read_maybe_empty(
597 _("It is highly recommended that the partition at offset 0\n"
598 "is UFS, EXT2FS filesystem or SunOS swap. Putting Linux swap\n"
599 "there may destroy your partition table and bootblock.\n"
600 "Type YES if you're very sure you would like that partition\n"
601 "tagged with 82 (Linux swap): "));
602 if (strcmp (line_ptr, _("YES\n")))
603 return;
604 }
605 switch (sys) {
606 case SUNOS_SWAP:
607 case LINUX_SWAP:
608 /* swaps are not mountable by default */
609 sunlabel->infos[i].flags |= 0x01;
610 break;
611 default:
612 /* assume other types are mountable;
613 user can change it anyway */
614 sunlabel->infos[i].flags &= ~0x01;
615 break;
616 }
617 sunlabel->infos[i].id = sys;
618}
619
620static void
621sun_list_table(int xtra)
622{
623 int i, w;
624
625 w = strlen(disk_device);
626 if (xtra)
627 printf(
628 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d rpm\n"
629 "%d cylinders, %d alternate cylinders, %d physical cylinders\n"
630 "%d extra sects/cyl, interleave %d:1\n"
631 "%s\n"
632 "Units = %s of %d * 512 bytes\n\n"),
633 disk_device, heads, sectors, SUN_SSWAP16(sunlabel->rspeed),
634 cylinders, SUN_SSWAP16(sunlabel->nacyl),
635 SUN_SSWAP16(sunlabel->pcylcount),
636 SUN_SSWAP16(sunlabel->sparecyl),
637 SUN_SSWAP16(sunlabel->ilfact),
638 (char *)sunlabel,
639 str_units(PLURAL), units_per_sector);
640 else
641 printf(
642 _("\nDisk %s (Sun disk label): %d heads, %d sectors, %d cylinders\n"
643 "Units = %s of %d * 512 bytes\n\n"),
644 disk_device, heads, sectors, cylinders,
645 str_units(PLURAL), units_per_sector);
646
647 printf(_("%*s Flag Start End Blocks Id System\n"),
648 w + 1, _("Device"));
649 for (i = 0 ; i < partitions; i++) {
650 if (sunlabel->partitions[i].num_sectors) {
651 uint32_t start = SUN_SSWAP32(sunlabel->partitions[i].start_cylinder) * heads * sectors;
652 uint32_t len = SUN_SSWAP32(sunlabel->partitions[i].num_sectors);
653 printf("%s %c%c %9ld %9ld %9ld%c %2x %s\n",
654 partname(disk_device, i+1, w), /* device */
655 (sunlabel->infos[i].flags & 0x01) ? 'u' : ' ', /* flags */
656 (sunlabel->infos[i].flags & 0x10) ? 'r' : ' ',
657 (long) scround(start), /* start */
658 (long) scround(start+len), /* end */
659 (long) len / 2, len & 1 ? '+' : ' ', /* odd flag on end */
660 sunlabel->infos[i].id, /* type id */
661 partition_type(sunlabel->infos[i].id)); /* type name */
662 }
663 }
664}
665
666#ifdef CONFIG_FEATURE_FDISK_ADVANCED
667
668static void
669sun_set_alt_cyl(void)
670{
671 sunlabel->nacyl =
672 SUN_SSWAP16(read_int(0,SUN_SSWAP16(sunlabel->nacyl), 65535, 0,
673 _("Number of alternate cylinders")));
674}
675
676static void
677sun_set_ncyl(int cyl)
678{
679 sunlabel->ncyl = SUN_SSWAP16(cyl);
680}
681
682static void
683sun_set_xcyl(void)
684{
685 sunlabel->sparecyl =
686 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->sparecyl), sectors, 0,
687 _("Extra sectors per cylinder")));
688}
689
690static void
691sun_set_ilfact(void)
692{
693 sunlabel->ilfact =
694 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->ilfact), 32, 0,
695 _("Interleave factor")));
696}
697
698static void
699sun_set_rspeed(void)
700{
701 sunlabel->rspeed =
702 SUN_SSWAP16(read_int(1, SUN_SSWAP16(sunlabel->rspeed), 100000, 0,
703 _("Rotation speed (rpm)")));
704}
705
706static void
707sun_set_pcylcount(void)
708{
709 sunlabel->pcylcount =
710 SUN_SSWAP16(read_int(0, SUN_SSWAP16(sunlabel->pcylcount), 65535, 0,
711 _("Number of physical cylinders")));
712}
713#endif /* CONFIG_FEATURE_FDISK_ADVANCED */
714
715static void
716sun_write_table(void)
717{
718 unsigned short *ush = (unsigned short *)sunlabel;
719 unsigned short csum = 0;
720
721 while (ush < (unsigned short *)(&sunlabel->csum))
722 csum ^= *ush++;
723 sunlabel->csum = csum;
724 if (lseek(fd, 0, SEEK_SET) < 0)
725 fdisk_fatal(unable_to_seek);
726 if (write(fd, sunlabel, SECTOR_SIZE) != SECTOR_SIZE)
727 fdisk_fatal(unable_to_write);
728}
729#endif /* SUN_LABEL */
diff --git a/util-linux/freeramdisk.c b/util-linux/freeramdisk.c
new file mode 100644
index 000000000..2293d3ee6
--- /dev/null
+++ b/util-linux/freeramdisk.c
@@ -0,0 +1,34 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * freeramdisk and fdflush implementations for busybox
4 *
5 * Copyright (C) 2000 and written by Emanuele Caratti <wiz@iol.it>
6 * Adjusted a bit by Erik Andersen <andersen@codepoet.org>
7 * Unified with fdflush by Tito Ragusa <farmatito@tiscali.it>
8 *
9 * Licensed under GPLv2, see file LICENSE in this tarball for details.
10 */
11
12#include "busybox.h"
13
14/* From <linux/fd.h> */
15#define FDFLUSH _IO(2,0x4b)
16
17int freeramdisk_main(int argc, char **argv)
18{
19 int result;
20 int fd;
21
22 if (argc != 2) bb_show_usage();
23
24 fd = xopen(argv[1], O_RDWR);
25
26 // Act like freeramdisk, fdflush, or both depending on configuration.
27 result = ioctl(fd, (ENABLE_FREERAMDISK && applet_name[1]=='r')
28 || !ENABLE_FDFLUSH ? BLKFLSBUF : FDFLUSH);
29
30 if (ENABLE_FEATURE_CLEAN_UP) close(fd);
31
32 if (result) bb_perror_msg_and_die("%s", argv[1]);
33 return EXIT_SUCCESS;
34}
diff --git a/util-linux/fsck_minix.c b/util-linux/fsck_minix.c
new file mode 100644
index 000000000..9c831bd59
--- /dev/null
+++ b/util-linux/fsck_minix.c
@@ -0,0 +1,1417 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * fsck.c - a file system consistency checker for Linux.
4 *
5 * (C) 1991, 1992 Linus Torvalds.
6 *
7 * Licensed under GPLv2, see file LICENSE in this tarball for details.
8 */
9
10/*
11 * 09.11.91 - made the first rudimentary functions
12 *
13 * 10.11.91 - updated, does checking, no repairs yet.
14 * Sent out to the mailing-list for testing.
15 *
16 * 14.11.91 - Testing seems to have gone well. Added some
17 * correction-code, and changed some functions.
18 *
19 * 15.11.91 - More correction code. Hopefully it notices most
20 * cases now, and tries to do something about them.
21 *
22 * 16.11.91 - More corrections (thanks to Mika Jalava). Most
23 * things seem to work now. Yeah, sure.
24 *
25 *
26 * 19.04.92 - Had to start over again from this old version, as a
27 * kernel bug ate my enhanced fsck in february.
28 *
29 * 28.02.93 - added support for different directory entry sizes..
30 *
31 * Sat Mar 6 18:59:42 1993, faith@cs.unc.edu: Output namelen with
32 * super-block information
33 *
34 * Sat Oct 9 11:17:11 1993, faith@cs.unc.edu: make exit status conform
35 * to that required by fsutil
36 *
37 * Mon Jan 3 11:06:52 1994 - Dr. Wettstein (greg%wind.uucp@plains.nodak.edu)
38 * Added support for file system valid flag. Also
39 * added program_version variable and output of
40 * program name and version number when program
41 * is executed.
42 *
43 * 30.10.94 - added support for v2 filesystem
44 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
45 *
46 * 10.12.94 - added test to prevent checking of mounted fs adapted
47 * from Theodore Ts'o's (tytso@athena.mit.edu) e2fsck
48 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
49 *
50 * 01.07.96 - Fixed the v2 fs stuff to use the right #defines and such
51 * for modern libcs (janl@math.uio.no, Nicolai Langfeldt)
52 *
53 * 02.07.96 - Added C bit fiddling routines from rmk@ecs.soton.ac.uk
54 * (Russell King). He made them for ARM. It would seem
55 * that the ARM is powerful enough to do this in C whereas
56 * i386 and m64k must use assembly to get it fast >:-)
57 * This should make minix fsck system-independent.
58 * (janl@math.uio.no, Nicolai Langfeldt)
59 *
60 * 04.11.96 - Added minor fixes from Andreas Schwab to avoid compiler
61 * warnings. Added mc68k bitops from
62 * Joerg Dorchain <dorchain@mpi-sb.mpg.de>.
63 *
64 * 06.11.96 - Added v2 code submitted by Joerg Dorchain, but written by
65 * Andreas Schwab.
66 *
67 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
68 * - added Native Language Support
69 *
70 *
71 * I've had no time to add comments - hopefully the function names
72 * are comments enough. As with all file system checkers, this assumes
73 * the file system is quiescent - don't use it on a mounted device
74 * unless you can be sure nobody is writing to it (and remember that the
75 * kernel can write to it when it searches for files).
76 *
77 * Usage: fsck [-larvsm] device
78 * -l for a listing of all the filenames
79 * -a for automatic repairs (not implemented)
80 * -r for repairs (interactive) (not implemented)
81 * -v for verbose (tells how many files)
82 * -s for super-block info
83 * -m for minix-like "mode not cleared" warnings
84 * -f force filesystem check even if filesystem marked as valid
85 *
86 * The device may be a block device or a image of one, but this isn't
87 * enforced (but it's not much fun on a character device :-).
88 */
89
90#include "busybox.h"
91#include <mntent.h>
92
93/*
94 * This is the original minix inode layout on disk.
95 * Note the 8-bit gid and atime and ctime.
96 */
97struct minix_inode {
98 uint16_t i_mode;
99 uint16_t i_uid;
100 uint32_t i_size;
101 uint32_t i_time;
102 uint8_t i_gid;
103 uint8_t i_nlinks;
104 uint16_t i_zone[9];
105};
106
107/*
108 * The new minix inode has all the time entries, as well as
109 * long block numbers and a third indirect block (7+1+1+1
110 * instead of 7+1+1). Also, some previously 8-bit values are
111 * now 16-bit. The inode is now 64 bytes instead of 32.
112 */
113struct minix2_inode {
114 uint16_t i_mode;
115 uint16_t i_nlinks;
116 uint16_t i_uid;
117 uint16_t i_gid;
118 uint32_t i_size;
119 uint32_t i_atime;
120 uint32_t i_mtime;
121 uint32_t i_ctime;
122 uint32_t i_zone[10];
123};
124
125enum {
126 MINIX_ROOT_INO = 1,
127 MINIX_LINK_MAX = 250,
128 MINIX2_LINK_MAX = 65530,
129
130 MINIX_I_MAP_SLOTS = 8,
131 MINIX_Z_MAP_SLOTS = 64,
132 MINIX_SUPER_MAGIC = 0x137F, /* original minix fs */
133 MINIX_SUPER_MAGIC2 = 0x138F, /* minix fs, 30 char names */
134 MINIX2_SUPER_MAGIC = 0x2468, /* minix V2 fs */
135 MINIX2_SUPER_MAGIC2 = 0x2478, /* minix V2 fs, 30 char names */
136 MINIX_VALID_FS = 0x0001, /* Clean fs. */
137 MINIX_ERROR_FS = 0x0002, /* fs has errors. */
138
139 MINIX_INODES_PER_BLOCK = ((BLOCK_SIZE)/(sizeof (struct minix_inode))),
140 MINIX2_INODES_PER_BLOCK = ((BLOCK_SIZE)/(sizeof (struct minix2_inode))),
141
142 MINIX_V1 = 0x0001, /* original minix fs */
143 MINIX_V2 = 0x0002 /* minix V2 fs */
144};
145
146#define INODE_VERSION(inode) inode->i_sb->u.minix_sb.s_version
147
148/*
149 * minix super-block data on disk
150 */
151struct minix_super_block {
152 uint16_t s_ninodes;
153 uint16_t s_nzones;
154 uint16_t s_imap_blocks;
155 uint16_t s_zmap_blocks;
156 uint16_t s_firstdatazone;
157 uint16_t s_log_zone_size;
158 uint32_t s_max_size;
159 uint16_t s_magic;
160 uint16_t s_state;
161 uint32_t s_zones;
162};
163
164struct minix_dir_entry {
165 uint16_t inode;
166 char name[0];
167};
168
169
170#define NAME_MAX 255 /* # chars in a file name */
171
172#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode)))
173
174#ifndef BLKGETSIZE
175#define BLKGETSIZE _IO(0x12,96) /* return device size */
176#endif
177
178#ifndef __linux__
179#define volatile
180#endif
181
182enum { ROOT_INO = 1 };
183
184#define UPPER(size,n) ((size+((n)-1))/(n))
185#define INODE_SIZE (sizeof(struct minix_inode))
186#ifdef CONFIG_FEATURE_MINIX2
187#define INODE_SIZE2 (sizeof(struct minix2_inode))
188#define INODE_BLOCKS UPPER(INODES, (version2 ? MINIX2_INODES_PER_BLOCK \
189 : MINIX_INODES_PER_BLOCK))
190#else
191#define INODE_BLOCKS UPPER(INODES, (MINIX_INODES_PER_BLOCK))
192#endif
193#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
194
195#define BITS_PER_BLOCK (BLOCK_SIZE<<3)
196
197static char *program_version = "1.2 - 11/11/96";
198static char *device_name;
199static int IN;
200static int repair, automatic, verbose, list, show, warn_mode, force;
201static int directory, regular, blockdev, chardev, links, symlinks, total;
202
203static int changed; /* flags if the filesystem has been changed */
204static int errors_uncorrected; /* flag if some error was not corrected */
205static int dirsize = 16;
206static int namelen = 14;
207static struct termios termios;
208static int termios_set;
209
210static char *inode_buffer;
211#define Inode (((struct minix_inode *) inode_buffer)-1)
212#define Inode2 (((struct minix2_inode *) inode_buffer)-1)
213static char super_block_buffer[BLOCK_SIZE];
214
215#define Super (*(struct minix_super_block *)super_block_buffer)
216#define INODES ((unsigned long)Super.s_ninodes)
217#ifdef CONFIG_FEATURE_MINIX2
218static int version2;
219#define ZONES ((unsigned long)(version2 ? Super.s_zones : Super.s_nzones))
220#else
221#define ZONES ((unsigned long)(Super.s_nzones))
222#endif
223#define IMAPS ((unsigned long)Super.s_imap_blocks)
224#define ZMAPS ((unsigned long)Super.s_zmap_blocks)
225#define FIRSTZONE ((unsigned long)Super.s_firstdatazone)
226#define ZONESIZE ((unsigned long)Super.s_log_zone_size)
227#define MAXSIZE ((unsigned long)Super.s_max_size)
228#define MAGIC (Super.s_magic)
229#define NORM_FIRSTZONE (2+IMAPS+ZMAPS+INODE_BLOCKS)
230
231static char *inode_map;
232static char *zone_map;
233
234static unsigned char *inode_count;
235static unsigned char *zone_count;
236
237static void recursive_check(unsigned int ino);
238#ifdef CONFIG_FEATURE_MINIX2
239static void recursive_check2(unsigned int ino);
240#endif
241
242static int bit(char *a, unsigned int i)
243{
244 return (a[i >> 3] & (1<<(i & 7))) != 0;
245}
246#define inode_in_use(x) (bit(inode_map,(x)))
247#define zone_in_use(x) (bit(zone_map,(x)-FIRSTZONE+1))
248
249#define mark_inode(x) (setbit(inode_map,(x)),changed=1)
250#define unmark_inode(x) (clrbit(inode_map,(x)),changed=1)
251
252#define mark_zone(x) (setbit(zone_map,(x)-FIRSTZONE+1),changed=1)
253#define unmark_zone(x) (clrbit(zone_map,(x)-FIRSTZONE+1),changed=1)
254
255static void leave(int) ATTRIBUTE_NORETURN;
256static void leave(int status)
257{
258 if (termios_set)
259 tcsetattr(0, TCSANOW, &termios);
260 exit(status);
261}
262
263static void die(const char *str)
264{
265 bb_error_msg("%s", str);
266 leave(8);
267}
268
269/* File-name data */
270enum { MAX_DEPTH = 32 };
271static int name_depth;
272static char *current_name;
273static char *name_component[MAX_DEPTH+1];
274
275/* Wed Feb 9 15:17:06 MST 2000 */
276/* dynamically allocate name_list (instead of making it static) */
277static void alloc_current_name(void)
278{
279 current_name = xmalloc(MAX_DEPTH * (BUFSIZ + 1));
280 current_name[0] = '/';
281 current_name[1] = '\0';
282 name_component[0] = &current_name[0];
283}
284
285#ifdef CONFIG_FEATURE_CLEAN_UP
286/* execute this atexit() to deallocate name_list[] */
287/* piptigger was here */
288static void free_current_name(void)
289{
290 free(current_name);
291}
292#endif
293
294static void push_filename(const char *name)
295{
296 // /dir/dir/dir/file
297 // ^ ^ ^
298 // [0] [1] [2] <-name_component[i]
299 if (name_depth < MAX_DEPTH) {
300 int len;
301 char *p = name_component[name_depth];
302 *p++ = '/';
303 len = sprintf(p, "%.*s", namelen, name);
304 name_component[name_depth + 1] = p + len;
305 }
306 name_depth++;
307}
308
309static void pop_filename(void) {
310 name_depth--;
311 if (name_depth < MAX_DEPTH) {
312 *name_component[name_depth] = '\0';
313 if (!name_depth) {
314 current_name[0] = '/';
315 current_name[1] = '\0';
316 }
317 }
318}
319
320static int ask(const char *string, int def)
321{
322 int c;
323
324 if (!repair) {
325 puts("");
326 errors_uncorrected = 1;
327 return 0;
328 }
329 if (automatic) {
330 puts("");
331 if (!def)
332 errors_uncorrected = 1;
333 return def;
334 }
335 printf(def ? "%s (y/n)? " : "%s (n/y)? ", string);
336 for (;;) {
337 fflush(stdout);
338 if ((c = getchar()) == EOF) {
339 if (!def)
340 errors_uncorrected = 1;
341 return def;
342 }
343 c = toupper(c);
344 if (c == 'Y') {
345 def = 1;
346 break;
347 } else if (c == 'N') {
348 def = 0;
349 break;
350 } else if (c == ' ' || c == '\n')
351 break;
352 }
353 if (def)
354 printf("y\n");
355 else {
356 printf("n\n");
357 errors_uncorrected = 1;
358 }
359 return def;
360}
361
362/*
363 * Make certain that we aren't checking a filesystem that is on a
364 * mounted partition. Code adapted from e2fsck, Copyright (C) 1993,
365 * 1994 Theodore Ts'o. Also licensed under GPL.
366 */
367static void check_mount(void)
368{
369 FILE *f;
370 struct mntent *mnt;
371 int cont;
372 int fd;
373
374 if ((f = setmntent(MOUNTED, "r")) == NULL)
375 return;
376 while ((mnt = getmntent(f)) != NULL)
377 if (strcmp(device_name, mnt->mnt_fsname) == 0)
378 break;
379 endmntent(f);
380 if (!mnt)
381 return;
382
383 /*
384 * If the root is mounted read-only, then /etc/mtab is
385 * probably not correct; so we won't issue a warning based on
386 * it.
387 */
388 fd = open(MOUNTED, O_RDWR);
389 if (fd < 0 && errno == EROFS)
390 return;
391 else
392 close(fd);
393
394 printf("%s is mounted. ", device_name);
395 cont = 0;
396 if (isatty(0) && isatty(1))
397 cont = ask("Do you really want to continue", 0);
398 if (!cont) {
399 printf("Check aborted\n");
400 exit(0);
401 }
402 return;
403}
404
405/*
406 * check_zone_nr checks to see that *nr is a valid zone nr. If it
407 * isn't, it will possibly be repaired. Check_zone_nr sets *corrected
408 * if an error was corrected, and returns the zone (0 for no zone
409 * or a bad zone-number).
410 */
411static int check_zone_nr2(uint32_t *nr, int *corrected)
412{
413 const char *msg;
414 if (!*nr)
415 return 0;
416 if (*nr < FIRSTZONE)
417 msg = "< FIRSTZONE";
418 else if (*nr >= ZONES)
419 msg = ">= ZONES";
420 else
421 return *nr;
422 printf("Zone nr %s in file '%s'. ", msg, current_name);
423 if (ask("Remove block", 1)) {
424 *nr = 0;
425 *corrected = 1;
426 }
427 return 0;
428}
429
430static int check_zone_nr(uint16_t *nr, int *corrected)
431{
432 uint32_t nr32 = *nr;
433 int r = check_zone_nr2(&nr32, corrected);
434 *nr = (uint16_t)nr32;
435 return r;
436}
437
438/*
439 * read-block reads block nr into the buffer at addr.
440 */
441static void read_block(unsigned int nr, char *addr)
442{
443 if (!nr) {
444 memset(addr, 0, BLOCK_SIZE);
445 return;
446 }
447 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET)) {
448 printf("%s: cannot seek to block in file '%s'\n",
449 bb_msg_read_error, current_name);
450 errors_uncorrected = 1;
451 memset(addr, 0, BLOCK_SIZE);
452 } else if (BLOCK_SIZE != read(IN, addr, BLOCK_SIZE)) {
453 printf("%s: bad block in file '%s'\n",
454 bb_msg_read_error, current_name);
455 errors_uncorrected = 1;
456 memset(addr, 0, BLOCK_SIZE);
457 }
458}
459
460/*
461 * write_block writes block nr to disk.
462 */
463static void write_block(unsigned int nr, char *addr)
464{
465 if (!nr)
466 return;
467 if (nr < FIRSTZONE || nr >= ZONES) {
468 printf("Internal error: trying to write bad block\n"
469 "Write request ignored\n");
470 errors_uncorrected = 1;
471 return;
472 }
473 if (BLOCK_SIZE * nr != lseek(IN, BLOCK_SIZE * nr, SEEK_SET))
474 die("Seek failed in write_block");
475 if (BLOCK_SIZE != write(IN, addr, BLOCK_SIZE)) {
476 printf("%s: bad block in file '%s'\n",
477 bb_msg_write_error, current_name);
478 errors_uncorrected = 1;
479 }
480}
481
482/*
483 * map_block calculates the absolute block nr of a block in a file.
484 * It sets 'changed' if the inode has needed changing, and re-writes
485 * any indirect blocks with errors.
486 */
487static int map_block(struct minix_inode *inode, unsigned int blknr)
488{
489 uint16_t ind[BLOCK_SIZE >> 1];
490 uint16_t dind[BLOCK_SIZE >> 1];
491 int blk_chg, block, result;
492
493 if (blknr < 7)
494 return check_zone_nr(inode->i_zone + blknr, &changed);
495 blknr -= 7;
496 if (blknr < 512) {
497 block = check_zone_nr(inode->i_zone + 7, &changed);
498 read_block(block, (char *) ind);
499 blk_chg = 0;
500 result = check_zone_nr(blknr + ind, &blk_chg);
501 if (blk_chg)
502 write_block(block, (char *) ind);
503 return result;
504 }
505 blknr -= 512;
506 block = check_zone_nr(inode->i_zone + 8, &changed);
507 read_block(block, (char *) dind);
508 blk_chg = 0;
509 result = check_zone_nr(dind + (blknr / 512), &blk_chg);
510 if (blk_chg)
511 write_block(block, (char *) dind);
512 block = result;
513 read_block(block, (char *) ind);
514 blk_chg = 0;
515 result = check_zone_nr(ind + (blknr % 512), &blk_chg);
516 if (blk_chg)
517 write_block(block, (char *) ind);
518 return result;
519}
520
521#ifdef CONFIG_FEATURE_MINIX2
522static int map_block2(struct minix2_inode *inode, unsigned int blknr)
523{
524 uint32_t ind[BLOCK_SIZE >> 2];
525 uint32_t dind[BLOCK_SIZE >> 2];
526 uint32_t tind[BLOCK_SIZE >> 2];
527 int blk_chg, block, result;
528
529 if (blknr < 7)
530 return check_zone_nr2(inode->i_zone + blknr, &changed);
531 blknr -= 7;
532 if (blknr < 256) {
533 block = check_zone_nr2(inode->i_zone + 7, &changed);
534 read_block(block, (char *) ind);
535 blk_chg = 0;
536 result = check_zone_nr2(blknr + ind, &blk_chg);
537 if (blk_chg)
538 write_block(block, (char *) ind);
539 return result;
540 }
541 blknr -= 256;
542 if (blknr >= 256 * 256) {
543 block = check_zone_nr2(inode->i_zone + 8, &changed);
544 read_block(block, (char *) dind);
545 blk_chg = 0;
546 result = check_zone_nr2(dind + blknr / 256, &blk_chg);
547 if (blk_chg)
548 write_block(block, (char *) dind);
549 block = result;
550 read_block(block, (char *) ind);
551 blk_chg = 0;
552 result = check_zone_nr2(ind + blknr % 256, &blk_chg);
553 if (blk_chg)
554 write_block(block, (char *) ind);
555 return result;
556 }
557 blknr -= 256 * 256;
558 block = check_zone_nr2(inode->i_zone + 9, &changed);
559 read_block(block, (char *) tind);
560 blk_chg = 0;
561 result = check_zone_nr2(tind + blknr / (256 * 256), &blk_chg);
562 if (blk_chg)
563 write_block(block, (char *) tind);
564 block = result;
565 read_block(block, (char *) dind);
566 blk_chg = 0;
567 result = check_zone_nr2(dind + (blknr / 256) % 256, &blk_chg);
568 if (blk_chg)
569 write_block(block, (char *) dind);
570 block = result;
571 read_block(block, (char *) ind);
572 blk_chg = 0;
573 result = check_zone_nr2(ind + blknr % 256, &blk_chg);
574 if (blk_chg)
575 write_block(block, (char *) ind);
576 return result;
577}
578#endif
579
580static void write_super_block(void)
581{
582 /*
583 * Set the state of the filesystem based on whether or not there
584 * are uncorrected errors. The filesystem valid flag is
585 * unconditionally set if we get this far.
586 */
587 Super.s_state |= MINIX_VALID_FS;
588 if (errors_uncorrected)
589 Super.s_state |= MINIX_ERROR_FS;
590 else
591 Super.s_state &= ~MINIX_ERROR_FS;
592
593 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
594 die("Seek failed in write_super_block");
595 if (BLOCK_SIZE != write(IN, super_block_buffer, BLOCK_SIZE))
596 die("Unable to write super-block");
597}
598
599static void write_tables(void)
600{
601 write_super_block();
602
603 if (IMAPS * BLOCK_SIZE != write(IN, inode_map, IMAPS * BLOCK_SIZE))
604 die("Unable to write inode map");
605 if (ZMAPS * BLOCK_SIZE != write(IN, zone_map, ZMAPS * BLOCK_SIZE))
606 die("Unable to write zone map");
607 if (INODE_BUFFER_SIZE != write(IN, inode_buffer, INODE_BUFFER_SIZE))
608 die("Unable to write inodes");
609}
610
611static void get_dirsize(void)
612{
613 int block;
614 char blk[BLOCK_SIZE];
615 int size;
616
617#ifdef CONFIG_FEATURE_MINIX2
618 if (version2)
619 block = Inode2[ROOT_INO].i_zone[0];
620 else
621#endif
622 block = Inode[ROOT_INO].i_zone[0];
623 read_block(block, blk);
624 for (size = 16; size < BLOCK_SIZE; size <<= 1) {
625 if (strcmp(blk + size + 2, "..") == 0) {
626 dirsize = size;
627 namelen = size - 2;
628 return;
629 }
630 }
631 /* use defaults */
632}
633
634static void read_superblock(void)
635{
636 if (BLOCK_SIZE != lseek(IN, BLOCK_SIZE, SEEK_SET))
637 die("Seek failed");
638 if (BLOCK_SIZE != read(IN, super_block_buffer, BLOCK_SIZE))
639 die("Unable to read super block");
640 /* already initialized to:
641 namelen = 14;
642 dirsize = 16;
643 version2 = 0;
644 */
645 if (MAGIC == MINIX_SUPER_MAGIC) {
646 } else if (MAGIC == MINIX_SUPER_MAGIC2) {
647 namelen = 30;
648 dirsize = 32;
649#ifdef CONFIG_FEATURE_MINIX2
650 } else if (MAGIC == MINIX2_SUPER_MAGIC) {
651 version2 = 1;
652 } else if (MAGIC == MINIX2_SUPER_MAGIC2) {
653 namelen = 30;
654 dirsize = 32;
655 version2 = 1;
656#endif
657 } else
658 die("Bad magic number in super-block");
659 if (ZONESIZE != 0 || BLOCK_SIZE != 1024)
660 die("Only 1k blocks/zones supported");
661 if (IMAPS * BLOCK_SIZE * 8 < INODES + 1)
662 die("Bad s_imap_blocks field in super-block");
663 if (ZMAPS * BLOCK_SIZE * 8 < ZONES - FIRSTZONE + 1)
664 die("Bad s_zmap_blocks field in super-block");
665}
666
667static void read_tables(void)
668{
669 inode_map = xzalloc(IMAPS * BLOCK_SIZE);
670 zone_map = xzalloc(ZMAPS * BLOCK_SIZE);
671 inode_buffer = xmalloc(INODE_BUFFER_SIZE);
672 inode_count = xmalloc(INODES + 1);
673 zone_count = xmalloc(ZONES);
674 if (IMAPS * BLOCK_SIZE != read(IN, inode_map, IMAPS * BLOCK_SIZE))
675 die("Unable to read inode map");
676 if (ZMAPS * BLOCK_SIZE != read(IN, zone_map, ZMAPS * BLOCK_SIZE))
677 die("Unable to read zone map");
678 if (INODE_BUFFER_SIZE != read(IN, inode_buffer, INODE_BUFFER_SIZE))
679 die("Unable to read inodes");
680 if (NORM_FIRSTZONE != FIRSTZONE) {
681 printf("Warning: Firstzone!=Norm_firstzone\n");
682 errors_uncorrected = 1;
683 }
684 get_dirsize();
685 if (show) {
686 printf("%ld inodes\n"
687 "%ld blocks\n"
688 "Firstdatazone=%ld (%ld)\n"
689 "Zonesize=%d\n"
690 "Maxsize=%ld\n"
691 "Filesystem state=%d\n"
692 "namelen=%d\n\n",
693 INODES,
694 ZONES,
695 FIRSTZONE, NORM_FIRSTZONE,
696 BLOCK_SIZE << ZONESIZE,
697 MAXSIZE,
698 Super.s_state,
699 namelen);
700 }
701}
702
703static struct minix_inode *get_inode(unsigned int nr)
704{
705 struct minix_inode *inode;
706
707 if (!nr || nr > INODES)
708 return NULL;
709 total++;
710 inode = Inode + nr;
711 if (!inode_count[nr]) {
712 if (!inode_in_use(nr)) {
713 printf("Inode %d is marked as 'unused', but it is used "
714 "for file '%s'\n", nr, current_name);
715 if (repair) {
716 if (ask("Mark as 'in use'", 1))
717 mark_inode(nr);
718 } else {
719 errors_uncorrected = 1;
720 }
721 }
722 if (S_ISDIR(inode->i_mode))
723 directory++;
724 else if (S_ISREG(inode->i_mode))
725 regular++;
726 else if (S_ISCHR(inode->i_mode))
727 chardev++;
728 else if (S_ISBLK(inode->i_mode))
729 blockdev++;
730 else if (S_ISLNK(inode->i_mode))
731 symlinks++;
732 else if (S_ISSOCK(inode->i_mode));
733 else if (S_ISFIFO(inode->i_mode));
734 else {
735 printf("%s has mode %05o\n", current_name, inode->i_mode);
736 }
737
738 } else
739 links++;
740 if (!++inode_count[nr]) {
741 printf("Warning: inode count too big\n");
742 inode_count[nr]--;
743 errors_uncorrected = 1;
744 }
745 return inode;
746}
747
748#ifdef CONFIG_FEATURE_MINIX2
749static struct minix2_inode *get_inode2(unsigned int nr)
750{
751 struct minix2_inode *inode;
752
753 if (!nr || nr > INODES)
754 return NULL;
755 total++;
756 inode = Inode2 + nr;
757 if (!inode_count[nr]) {
758 if (!inode_in_use(nr)) {
759 printf("Inode %d is marked as 'unused', but it is used "
760 "for file '%s'\n", nr, current_name);
761 if (repair) {
762 if (ask("Mark as 'in use'", 1))
763 mark_inode(nr);
764 else
765 errors_uncorrected = 1;
766 }
767 }
768 if (S_ISDIR(inode->i_mode))
769 directory++;
770 else if (S_ISREG(inode->i_mode))
771 regular++;
772 else if (S_ISCHR(inode->i_mode))
773 chardev++;
774 else if (S_ISBLK(inode->i_mode))
775 blockdev++;
776 else if (S_ISLNK(inode->i_mode))
777 symlinks++;
778 else if (S_ISSOCK(inode->i_mode));
779 else if (S_ISFIFO(inode->i_mode));
780 else {
781 printf("%s has mode %05o\n", current_name, inode->i_mode);
782 }
783 } else
784 links++;
785 if (!++inode_count[nr]) {
786 printf("Warning: inode count too big\n");
787 inode_count[nr]--;
788 errors_uncorrected = 1;
789 }
790 return inode;
791}
792#endif
793
794static void check_root(void)
795{
796 struct minix_inode *inode = Inode + ROOT_INO;
797
798 if (!inode || !S_ISDIR(inode->i_mode))
799 die("Root inode isn't a directory");
800}
801
802#ifdef CONFIG_FEATURE_MINIX2
803static void check_root2(void)
804{
805 struct minix2_inode *inode = Inode2 + ROOT_INO;
806
807 if (!inode || !S_ISDIR(inode->i_mode))
808 die("Root inode isn't a directory");
809}
810#endif
811
812static int add_zone(uint16_t *znr, int *corrected)
813{
814 int result;
815 int block;
816
817 result = 0;
818 block = check_zone_nr(znr, corrected);
819 if (!block)
820 return 0;
821 if (zone_count[block]) {
822 printf("Already used block is reused in file '%s'. ",
823 current_name);
824 if (ask("Clear", 1)) {
825 *znr = 0;
826 block = 0;
827 *corrected = 1;
828 return 0;
829 }
830 }
831 if (!zone_in_use(block)) {
832 printf("Block %d in file '%s' is marked as 'unused'. ",
833 block, current_name);
834 if (ask("Correct", 1))
835 mark_zone(block);
836 }
837 if (!++zone_count[block])
838 zone_count[block]--;
839 return block;
840}
841
842#ifdef CONFIG_FEATURE_MINIX2
843static int add_zone2(uint32_t *znr, int *corrected)
844{
845 int result;
846 int block;
847
848 result = 0;
849 block = check_zone_nr2(znr, corrected);
850 if (!block)
851 return 0;
852 if (zone_count[block]) {
853 printf("Already used block is reused in file '%s'. ",
854 current_name);
855 if (ask("Clear", 1)) {
856 *znr = 0;
857 block = 0;
858 *corrected = 1;
859 return 0;
860 }
861 }
862 if (!zone_in_use(block)) {
863 printf("Block %d in file '%s' is marked as 'unused'. ",
864 block, current_name);
865 if (ask("Correct", 1))
866 mark_zone(block);
867 }
868 if (!++zone_count[block])
869 zone_count[block]--;
870 return block;
871}
872#endif
873
874static void add_zone_ind(uint16_t *znr, int *corrected)
875{
876 static char blk[BLOCK_SIZE];
877 int i, chg_blk = 0;
878 int block;
879
880 block = add_zone(znr, corrected);
881 if (!block)
882 return;
883 read_block(block, blk);
884 for (i = 0; i < (BLOCK_SIZE >> 1); i++)
885 add_zone(i + (uint16_t *) blk, &chg_blk);
886 if (chg_blk)
887 write_block(block, blk);
888}
889
890#ifdef CONFIG_FEATURE_MINIX2
891static void add_zone_ind2(uint32_t *znr, int *corrected)
892{
893 static char blk[BLOCK_SIZE];
894 int i, chg_blk = 0;
895 int block;
896
897 block = add_zone2(znr, corrected);
898 if (!block)
899 return;
900 read_block(block, blk);
901 for (i = 0; i < BLOCK_SIZE >> 2; i++)
902 add_zone2(i + (uint32_t *) blk, &chg_blk);
903 if (chg_blk)
904 write_block(block, blk);
905}
906#endif
907
908static void add_zone_dind(uint16_t *znr, int *corrected)
909{
910 static char blk[BLOCK_SIZE];
911 int i, blk_chg = 0;
912 int block;
913
914 block = add_zone(znr, corrected);
915 if (!block)
916 return;
917 read_block(block, blk);
918 for (i = 0; i < (BLOCK_SIZE >> 1); i++)
919 add_zone_ind(i + (uint16_t *) blk, &blk_chg);
920 if (blk_chg)
921 write_block(block, blk);
922}
923
924#ifdef CONFIG_FEATURE_MINIX2
925static void add_zone_dind2(uint32_t *znr, int *corrected)
926{
927 static char blk[BLOCK_SIZE];
928 int i, blk_chg = 0;
929 int block;
930
931 block = add_zone2(znr, corrected);
932 if (!block)
933 return;
934 read_block(block, blk);
935 for (i = 0; i < BLOCK_SIZE >> 2; i++)
936 add_zone_ind2(i + (uint32_t *) blk, &blk_chg);
937 if (blk_chg)
938 write_block(block, blk);
939}
940
941static void add_zone_tind2(uint32_t *znr, int *corrected)
942{
943 static char blk[BLOCK_SIZE];
944 int i, blk_chg = 0;
945 int block;
946
947 block = add_zone2(znr, corrected);
948 if (!block)
949 return;
950 read_block(block, blk);
951 for (i = 0; i < BLOCK_SIZE >> 2; i++)
952 add_zone_dind2(i + (uint32_t *) blk, &blk_chg);
953 if (blk_chg)
954 write_block(block, blk);
955}
956#endif
957
958static void check_zones(unsigned int i)
959{
960 struct minix_inode *inode;
961
962 if (!i || i > INODES)
963 return;
964 if (inode_count[i] > 1) /* have we counted this file already? */
965 return;
966 inode = Inode + i;
967 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode) &&
968 !S_ISLNK(inode->i_mode)) return;
969 for (i = 0; i < 7; i++)
970 add_zone(i + inode->i_zone, &changed);
971 add_zone_ind(7 + inode->i_zone, &changed);
972 add_zone_dind(8 + inode->i_zone, &changed);
973}
974
975#ifdef CONFIG_FEATURE_MINIX2
976static void check_zones2(unsigned int i)
977{
978 struct minix2_inode *inode;
979
980 if (!i || i > INODES)
981 return;
982 if (inode_count[i] > 1) /* have we counted this file already? */
983 return;
984 inode = Inode2 + i;
985 if (!S_ISDIR(inode->i_mode) && !S_ISREG(inode->i_mode)
986 && !S_ISLNK(inode->i_mode))
987 return;
988 for (i = 0; i < 7; i++)
989 add_zone2(i + inode->i_zone, &changed);
990 add_zone_ind2(7 + inode->i_zone, &changed);
991 add_zone_dind2(8 + inode->i_zone, &changed);
992 add_zone_tind2(9 + inode->i_zone, &changed);
993}
994#endif
995
996static void check_file(struct minix_inode *dir, unsigned int offset)
997{
998 static char blk[BLOCK_SIZE];
999 struct minix_inode *inode;
1000 int ino;
1001 char *name;
1002 int block;
1003
1004 block = map_block(dir, offset / BLOCK_SIZE);
1005 read_block(block, blk);
1006 name = blk + (offset % BLOCK_SIZE) + 2;
1007 ino = *(uint16_t *) (name - 2);
1008 if (ino > INODES) {
1009 printf("%s contains a bad inode number for file '%.*s'. ",
1010 current_name, namelen, name);
1011 if (ask("Remove", 1)) {
1012 *(uint16_t *) (name - 2) = 0;
1013 write_block(block, blk);
1014 }
1015 ino = 0;
1016 }
1017 push_filename(name);
1018 inode = get_inode(ino);
1019 pop_filename();
1020 if (!offset) {
1021 if (!inode || strcmp(".", name)) {
1022 printf("%s: bad directory: '.' isn't first\n", current_name);
1023 errors_uncorrected = 1;
1024 } else
1025 return;
1026 }
1027 if (offset == dirsize) {
1028 if (!inode || strcmp("..", name)) {
1029 printf("%s: bad directory: '..' isn't second\n", current_name);
1030 errors_uncorrected = 1;
1031 } else
1032 return;
1033 }
1034 if (!inode)
1035 return;
1036 push_filename(name);
1037 if (list) {
1038 if (verbose)
1039 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
1040 printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
1041 }
1042 check_zones(ino);
1043 if (inode && S_ISDIR(inode->i_mode))
1044 recursive_check(ino);
1045 pop_filename();
1046 return;
1047}
1048
1049#ifdef CONFIG_FEATURE_MINIX2
1050static void check_file2(struct minix2_inode *dir, unsigned int offset)
1051{
1052 static char blk[BLOCK_SIZE];
1053 struct minix2_inode *inode;
1054 int ino;
1055 char *name;
1056 int block;
1057
1058 block = map_block2(dir, offset / BLOCK_SIZE);
1059 read_block(block, blk);
1060 name = blk + (offset % BLOCK_SIZE) + 2;
1061 ino = *(uint16_t *) (name - 2);
1062 if (ino > INODES) {
1063 printf("%s contains a bad inode number for file '%.*s'. ",
1064 current_name, namelen, name);
1065 if (ask("Remove", 1)) {
1066 *(uint16_t *) (name - 2) = 0;
1067 write_block(block, blk);
1068 }
1069 ino = 0;
1070 }
1071 push_filename(name);
1072 inode = get_inode2(ino);
1073 pop_filename();
1074 if (!offset) {
1075 if (!inode || strcmp(".", name)) {
1076 printf("%s: bad directory: '.' isn't first\n", current_name);
1077 errors_uncorrected = 1;
1078 } else
1079 return;
1080 }
1081 if (offset == dirsize) {
1082 if (!inode || strcmp("..", name)) {
1083 printf("%s: bad directory: '..' isn't second\n", current_name);
1084 errors_uncorrected = 1;
1085 } else
1086 return;
1087 }
1088 if (!inode)
1089 return;
1090 push_filename(name);
1091 if (list) {
1092 if (verbose)
1093 printf("%6d %07o %3d ", ino, inode->i_mode, inode->i_nlinks);
1094 printf("%s%s\n", current_name, S_ISDIR(inode->i_mode) ? ":" : "");
1095 }
1096 check_zones2(ino);
1097 if (inode && S_ISDIR(inode->i_mode))
1098 recursive_check2(ino);
1099 pop_filename();
1100 return;
1101}
1102#endif
1103
1104static void recursive_check(unsigned int ino)
1105{
1106 struct minix_inode *dir;
1107 unsigned int offset;
1108
1109 dir = Inode + ino;
1110 if (!S_ISDIR(dir->i_mode))
1111 die("Internal error");
1112 if (dir->i_size < 2 * dirsize) {
1113 printf("%s: bad directory: size<32", current_name);
1114 errors_uncorrected = 1;
1115 }
1116 for (offset = 0; offset < dir->i_size; offset += dirsize)
1117 check_file(dir, offset);
1118}
1119
1120#ifdef CONFIG_FEATURE_MINIX2
1121static void recursive_check2(unsigned int ino)
1122{
1123 struct minix2_inode *dir;
1124 unsigned int offset;
1125
1126 dir = Inode2 + ino;
1127 if (!S_ISDIR(dir->i_mode))
1128 die("Internal error");
1129 if (dir->i_size < 2 * dirsize) {
1130 printf("%s: bad directory: size<32", current_name);
1131 errors_uncorrected = 1;
1132 }
1133 for (offset = 0; offset < dir->i_size; offset += dirsize)
1134 check_file2(dir, offset);
1135}
1136#endif
1137
1138static int bad_zone(int i)
1139{
1140 char buffer[1024];
1141
1142 if (BLOCK_SIZE * i != lseek(IN, BLOCK_SIZE * i, SEEK_SET))
1143 die("Seek failed in bad_zone");
1144 return (BLOCK_SIZE != read(IN, buffer, BLOCK_SIZE));
1145}
1146
1147static void check_counts(void)
1148{
1149 int i;
1150
1151 for (i = 1; i <= INODES; i++) {
1152 if (warn_mode && Inode[i].i_mode && !inode_in_use(i)) {
1153 printf("Inode %d has non-zero mode. ", i);
1154 if (ask("Clear", 1)) {
1155 Inode[i].i_mode = 0;
1156 changed = 1;
1157 }
1158 }
1159 if (!inode_count[i]) {
1160 if (!inode_in_use(i))
1161 continue;
1162 printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
1163 if (ask("Clear", 1))
1164 unmark_inode(i);
1165 continue;
1166 }
1167 if (!inode_in_use(i)) {
1168 printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
1169 if (ask("Set", 1))
1170 mark_inode(i);
1171 }
1172 if (Inode[i].i_nlinks != inode_count[i]) {
1173 printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
1174 i, Inode[i].i_mode, Inode[i].i_nlinks, inode_count[i]);
1175 if (ask("Set i_nlinks to count", 1)) {
1176 Inode[i].i_nlinks = inode_count[i];
1177 changed = 1;
1178 }
1179 }
1180 }
1181 for (i = FIRSTZONE; i < ZONES; i++) {
1182 if (zone_in_use(i) == zone_count[i])
1183 continue;
1184 if (!zone_count[i]) {
1185 if (bad_zone(i))
1186 continue;
1187 printf("Zone %d is marked 'in use', but no file uses it. ", i);
1188 if (ask("Unmark", 1))
1189 unmark_zone(i);
1190 continue;
1191 }
1192 printf("Zone %d: %sin use, counted=%d\n",
1193 i, zone_in_use(i) ? "" : "not ", zone_count[i]);
1194 }
1195}
1196
1197#ifdef CONFIG_FEATURE_MINIX2
1198static void check_counts2(void)
1199{
1200 int i;
1201
1202 for (i = 1; i <= INODES; i++) {
1203 if (warn_mode && Inode2[i].i_mode && !inode_in_use(i)) {
1204 printf("Inode %d has non-zero mode. ", i);
1205 if (ask("Clear", 1)) {
1206 Inode2[i].i_mode = 0;
1207 changed = 1;
1208 }
1209 }
1210 if (!inode_count[i]) {
1211 if (!inode_in_use(i))
1212 continue;
1213 printf("Unused inode %d is marked as 'used' in the bitmap. ", i);
1214 if (ask("Clear", 1))
1215 unmark_inode(i);
1216 continue;
1217 }
1218 if (!inode_in_use(i)) {
1219 printf("Inode %d is used, but marked as 'unused' in the bitmap. ", i);
1220 if (ask("Set", 1))
1221 mark_inode(i);
1222 }
1223 if (Inode2[i].i_nlinks != inode_count[i]) {
1224 printf("Inode %d (mode=%07o), i_nlinks=%d, counted=%d. ",
1225 i, Inode2[i].i_mode, Inode2[i].i_nlinks,
1226 inode_count[i]);
1227 if (ask("Set i_nlinks to count", 1)) {
1228 Inode2[i].i_nlinks = inode_count[i];
1229 changed = 1;
1230 }
1231 }
1232 }
1233 for (i = FIRSTZONE; i < ZONES; i++) {
1234 if (zone_in_use(i) == zone_count[i])
1235 continue;
1236 if (!zone_count[i]) {
1237 if (bad_zone(i))
1238 continue;
1239 printf("Zone %d is marked 'in use', but no file uses it. ", i);
1240 if (ask("Unmark", 1))
1241 unmark_zone(i);
1242 continue;
1243 }
1244 printf("Zone %d: %sin use, counted=%d\n",
1245 i, zone_in_use(i) ? "" : "not ", zone_count[i]);
1246 }
1247}
1248#endif
1249
1250static void check(void)
1251{
1252 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
1253 memset(zone_count, 0, ZONES * sizeof(*zone_count));
1254 check_zones(ROOT_INO);
1255 recursive_check(ROOT_INO);
1256 check_counts();
1257}
1258
1259#ifdef CONFIG_FEATURE_MINIX2
1260static void check2(void)
1261{
1262 memset(inode_count, 0, (INODES + 1) * sizeof(*inode_count));
1263 memset(zone_count, 0, ZONES * sizeof(*zone_count));
1264 check_zones2(ROOT_INO);
1265 recursive_check2(ROOT_INO);
1266 check_counts2();
1267}
1268#endif
1269
1270int fsck_minix_main(int argc, char **argv)
1271{
1272 struct termios tmp;
1273 int retcode = 0;
1274
1275 alloc_current_name();
1276#ifdef CONFIG_FEATURE_CLEAN_UP
1277 /* Don't bother to free memory. Exit does
1278 * that automagically, so we can save a few bytes */
1279 atexit(free_current_name);
1280#endif
1281
1282 if (INODE_SIZE * MINIX_INODES_PER_BLOCK != BLOCK_SIZE)
1283 die("Bad inode size");
1284#ifdef CONFIG_FEATURE_MINIX2
1285 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
1286 die("Bad v2 inode size");
1287#endif
1288 while (argc-- > 1) {
1289 argv++;
1290 if (argv[0][0] != '-') {
1291 if (device_name)
1292 bb_show_usage();
1293 else
1294 device_name = argv[0];
1295 } else
1296 while (*++argv[0])
1297 switch (argv[0][0]) {
1298 case 'l':
1299 list = 1;
1300 break;
1301 case 'a':
1302 automatic = 1;
1303 repair = 1;
1304 break;
1305 case 'r':
1306 automatic = 0;
1307 repair = 1;
1308 break;
1309 case 'v':
1310 verbose = 1;
1311 break;
1312 case 's':
1313 show = 1;
1314 break;
1315 case 'm':
1316 warn_mode = 1;
1317 break;
1318 case 'f':
1319 force = 1;
1320 break;
1321 default:
1322 bb_show_usage();
1323 }
1324 }
1325 if (!device_name)
1326 bb_show_usage();
1327 check_mount(); /* trying to check a mounted filesystem? */
1328 if (repair && !automatic) {
1329 if (!isatty(0) || !isatty(1))
1330 die("Need terminal for interactive repairs");
1331 }
1332 IN = open(device_name, repair ? O_RDWR : O_RDONLY);
1333 if (IN < 0){
1334 printf("Unable to open device '%s'\n", device_name);
1335 leave(8);
1336 }
1337 sync(); /* paranoia? */
1338 read_superblock();
1339
1340 /*
1341 * Determine whether or not we should continue with the checking.
1342 * This is based on the status of the filesystem valid and error
1343 * flags and whether or not the -f switch was specified on the
1344 * command line.
1345 */
1346 printf("%s, %s\n", applet_name, program_version);
1347 if (!(Super.s_state & MINIX_ERROR_FS) &&
1348 (Super.s_state & MINIX_VALID_FS) && !force) {
1349 if (repair)
1350 printf("%s is clean, check is skipped\n", device_name);
1351 return retcode;
1352 } else if (force)
1353 printf("Forcing filesystem check on %s\n", device_name);
1354 else if (repair)
1355 printf("Filesystem on %s is dirty, needs checking\n",
1356 device_name);
1357
1358 read_tables();
1359
1360 if (repair && !automatic) {
1361 tcgetattr(0, &termios);
1362 tmp = termios;
1363 tmp.c_lflag &= ~(ICANON | ECHO);
1364 tcsetattr(0, TCSANOW, &tmp);
1365 termios_set = 1;
1366 }
1367#ifdef CONFIG_FEATURE_MINIX2
1368 if (version2) {
1369 check_root2();
1370 check2();
1371 } else
1372#endif
1373 {
1374 check_root();
1375 check();
1376 }
1377 if (verbose) {
1378 int i, free_cnt;
1379
1380 for (i = 1, free_cnt = 0; i <= INODES; i++)
1381 if (!inode_in_use(i))
1382 free_cnt++;
1383 printf("\n%6ld inodes used (%ld%%)\n", (INODES - free_cnt),
1384 100 * (INODES - free_cnt) / INODES);
1385 for (i = FIRSTZONE, free_cnt = 0; i < ZONES; i++)
1386 if (!zone_in_use(i))
1387 free_cnt++;
1388 printf("%6ld zones used (%ld%%)\n\n"
1389 "%6d regular files\n"
1390 "%6d directories\n"
1391 "%6d character device files\n"
1392 "%6d block device files\n"
1393 "%6d links\n"
1394 "%6d symbolic links\n"
1395 "------\n"
1396 "%6d files\n",
1397 (ZONES - free_cnt), 100 * (ZONES - free_cnt) / ZONES,
1398 regular, directory, chardev, blockdev,
1399 links - 2 * directory + 1, symlinks,
1400 total - 2 * directory + 1);
1401 }
1402 if (changed) {
1403 write_tables();
1404 printf("FILE SYSTEM HAS BEEN CHANGED\n");
1405 sync();
1406 } else if (repair)
1407 write_super_block();
1408
1409 if (repair && !automatic)
1410 tcsetattr(0, TCSANOW, &termios);
1411
1412 if (changed)
1413 retcode += 3;
1414 if (errors_uncorrected)
1415 retcode += 4;
1416 return retcode;
1417}
diff --git a/util-linux/getopt.c b/util-linux/getopt.c
new file mode 100644
index 000000000..64f568aa9
--- /dev/null
+++ b/util-linux/getopt.c
@@ -0,0 +1,365 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * getopt.c - Enhanced implementation of BSD getopt(1)
4 * Copyright (c) 1997, 1998, 1999, 2000 Frodo Looijaard <frodol@dds.nl>
5 *
6 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
7 */
8
9/*
10 * Version 1.0-b4: Tue Sep 23 1997. First public release.
11 * Version 1.0: Wed Nov 19 1997.
12 * Bumped up the version number to 1.0
13 * Fixed minor typo (CSH instead of TCSH)
14 * Version 1.0.1: Tue Jun 3 1998
15 * Fixed sizeof instead of strlen bug
16 * Bumped up the version number to 1.0.1
17 * Version 1.0.2: Thu Jun 11 1998 (not present)
18 * Fixed gcc-2.8.1 warnings
19 * Fixed --version/-V option (not present)
20 * Version 1.0.5: Tue Jun 22 1999
21 * Make -u option work (not present)
22 * Version 1.0.6: Tue Jun 27 2000
23 * No important changes
24 * Version 1.1.0: Tue Jun 30 2000
25 * Added NLS support (partly written by Arkadiusz Mi<B6>kiewicz
26 * <misiek@misiek.eu.org>)
27 * Ported to Busybox - Alfred M. Szmidt <ams@trillian.itslinux.org>
28 * Removed --version/-V and --help/-h in
29 * Removed parse_error(), using bb_error_msg() from Busybox instead
30 * Replaced our_malloc with xmalloc and our_realloc with xrealloc
31 *
32 */
33
34#include "busybox.h"
35#include <getopt.h>
36
37/* NON_OPT is the code that is returned when a non-option is found in '+'
38 mode */
39enum {
40 NON_OPT = 1,
41/* LONG_OPT is the code that is returned when a long option is found. */
42 LONG_OPT = 2
43};
44
45/* The shells recognized. */
46typedef enum {BASH,TCSH} shell_t;
47
48
49/* Some global variables that tells us how to parse. */
50static shell_t shell=BASH; /* The shell we generate output for. */
51static int quiet_errors; /* 0 is not quiet. */
52static int quiet_output; /* 0 is not quiet. */
53static int quote=1; /* 1 is do quote. */
54static int alternative; /* 0 is getopt_long, 1 is getopt_long_only */
55
56/* Function prototypes */
57static const char *normalize(const char *arg);
58static int generate_output(char * argv[],int argc,const char *optstr,
59 const struct option *longopts);
60static void add_long_options(char *options);
61static void add_longopt(const char *name,int has_arg);
62static void set_shell(const char *new_shell);
63
64
65/*
66 * This function 'normalizes' a single argument: it puts single quotes around
67 * it and escapes other special characters. If quote is false, it just
68 * returns its argument.
69 * Bash only needs special treatment for single quotes; tcsh also recognizes
70 * exclamation marks within single quotes, and nukes whitespace.
71 * This function returns a pointer to a buffer that is overwritten by
72 * each call.
73 */
74const char *normalize(const char *arg)
75{
76 static char *BUFFER=NULL;
77 const char *argptr=arg;
78 char *bufptr;
79
80 free(BUFFER);
81
82 if (!quote) { /* Just copy arg */
83 BUFFER=xstrdup(arg);
84 return BUFFER;
85 }
86
87 /* Each character in arg may take up to four characters in the result:
88 For a quote we need a closing quote, a backslash, a quote and an
89 opening quote! We need also the global opening and closing quote,
90 and one extra character for '\0'. */
91 BUFFER=xmalloc(strlen(arg)*4+3);
92
93 bufptr=BUFFER;
94 *bufptr++='\'';
95
96 while (*argptr) {
97 if (*argptr == '\'') {
98 /* Quote: replace it with: '\'' */
99 *bufptr++='\'';
100 *bufptr++='\\';
101 *bufptr++='\'';
102 *bufptr++='\'';
103 } else if (shell==TCSH && *argptr=='!') {
104 /* Exclamation mark: replace it with: \! */
105 *bufptr++='\'';
106 *bufptr++='\\';
107 *bufptr++='!';
108 *bufptr++='\'';
109 } else if (shell==TCSH && *argptr=='\n') {
110 /* Newline: replace it with: \n */
111 *bufptr++='\\';
112 *bufptr++='n';
113 } else if (shell==TCSH && isspace(*argptr)) {
114 /* Non-newline whitespace: replace it with \<ws> */
115 *bufptr++='\'';
116 *bufptr++='\\';
117 *bufptr++=*argptr;
118 *bufptr++='\'';
119 } else
120 /* Just copy */
121 *bufptr++=*argptr;
122 argptr++;
123 }
124 *bufptr++='\'';
125 *bufptr++='\0';
126 return BUFFER;
127}
128
129/*
130 * Generate the output. argv[0] is the program name (used for reporting errors).
131 * argv[1..] contains the options to be parsed. argc must be the number of
132 * elements in argv (ie. 1 if there are no options, only the program name),
133 * optstr must contain the short options, and longopts the long options.
134 * Other settings are found in global variables.
135 */
136int generate_output(char * argv[],int argc,const char *optstr,
137 const struct option *longopts)
138{
139 int exit_code = 0; /* We assume everything will be OK */
140 int opt;
141 int longindex;
142 const char *charptr;
143
144 if (quiet_errors) /* No error reporting from getopt(3) */
145 opterr=0;
146 optind=0; /* Reset getopt(3) */
147
148 while ((opt = (alternative?
149 getopt_long_only(argc,argv,optstr,longopts,&longindex):
150 getopt_long(argc,argv,optstr,longopts,&longindex)))
151 != EOF)
152 if (opt == '?' || opt == ':' )
153 exit_code = 1;
154 else if (!quiet_output) {
155 if (opt == LONG_OPT) {
156 printf(" --%s",longopts[longindex].name);
157 if (longopts[longindex].has_arg)
158 printf(" %s",
159 normalize(optarg?optarg:""));
160 } else if (opt == NON_OPT)
161 printf(" %s",normalize(optarg));
162 else {
163 printf(" -%c",opt);
164 charptr = strchr(optstr,opt);
165 if (charptr != NULL && *++charptr == ':')
166 printf(" %s",
167 normalize(optarg?optarg:""));
168 }
169 }
170
171 if (! quiet_output) {
172 printf(" --");
173 while (optind < argc)
174 printf(" %s",normalize(argv[optind++]));
175 puts("");
176 }
177 return exit_code;
178}
179
180static struct option *long_options;
181static int long_options_length; /* Length of array */
182static int long_options_nr; /* Nr of used elements in array */
183enum { LONG_OPTIONS_INCR = 10 };
184#define init_longopt() add_longopt(NULL,0)
185
186/* Register a long option. The contents of name is copied. */
187void add_longopt(const char *name, int has_arg)
188{
189 if (!name) { /* init */
190 free(long_options);
191 long_options=NULL;
192 long_options_length=0;
193 long_options_nr=0;
194 }
195
196 if (long_options_nr == long_options_length) {
197 long_options_length += LONG_OPTIONS_INCR;
198 long_options=xrealloc(long_options,
199 sizeof(struct option) *
200 long_options_length);
201 }
202
203 long_options[long_options_nr].name=NULL;
204 long_options[long_options_nr].has_arg=0;
205 long_options[long_options_nr].flag=NULL;
206 long_options[long_options_nr].val=0;
207
208 if (long_options_nr) { /* Not for init! */
209 long_options[long_options_nr-1].has_arg=has_arg;
210 long_options[long_options_nr-1].flag=NULL;
211 long_options[long_options_nr-1].val=LONG_OPT;
212 long_options[long_options_nr-1].name=xstrdup(name);
213 }
214 long_options_nr++;
215}
216
217
218/*
219 * Register several long options. options is a string of long options,
220 * separated by commas or whitespace.
221 * This nukes options!
222 */
223void add_long_options(char *options)
224{
225 int arg_opt, tlen;
226 char *tokptr=strtok(options,", \t\n");
227 while (tokptr) {
228 arg_opt=no_argument;
229 tlen=strlen(tokptr);
230 if (tlen > 0) {
231 if (tokptr[tlen-1] == ':') {
232 if (tlen > 1 && tokptr[tlen-2] == ':') {
233 tokptr[tlen-2]='\0';
234 tlen -= 2;
235 arg_opt=optional_argument;
236 } else {
237 tokptr[tlen-1]='\0';
238 tlen -= 1;
239 arg_opt=required_argument;
240 }
241 if (tlen == 0)
242 bb_error_msg("empty long option after -l or --long argument");
243 }
244 add_longopt(tokptr,arg_opt);
245 }
246 tokptr=strtok(NULL,", \t\n");
247 }
248}
249
250void set_shell(const char *new_shell)
251{
252 if (!strcmp(new_shell,"bash"))
253 shell=BASH;
254 else if (!strcmp(new_shell,"tcsh"))
255 shell=TCSH;
256 else if (!strcmp(new_shell,"sh"))
257 shell=BASH;
258 else if (!strcmp(new_shell,"csh"))
259 shell=TCSH;
260 else
261 bb_error_msg("unknown shell after -s or --shell argument");
262}
263
264
265/* Exit codes:
266 * 0) No errors, successful operation.
267 * 1) getopt(3) returned an error.
268 * 2) A problem with parameter parsing for getopt(1).
269 * 3) Internal error, out of memory
270 * 4) Returned for -T
271 */
272
273static const struct option longopts[]=
274{
275 {"options",required_argument,NULL,'o'},
276 {"longoptions",required_argument,NULL,'l'},
277 {"quiet",no_argument,NULL,'q'},
278 {"quiet-output",no_argument,NULL,'Q'},
279 {"shell",required_argument,NULL,'s'},
280 {"test",no_argument,NULL,'T'},
281 {"unquoted",no_argument,NULL,'u'},
282 {"alternative",no_argument,NULL,'a'},
283 {"name",required_argument,NULL,'n'},
284 {NULL,0,NULL,0}
285};
286
287/* Stop scanning as soon as a non-option argument is found! */
288static const char shortopts[]="+ao:l:n:qQs:Tu";
289
290
291int getopt_main(int argc, char *argv[])
292{
293 const char *optstr = NULL;
294 char *name = NULL;
295 int opt;
296 int compatible=0;
297
298 init_longopt();
299
300 if (getenv("GETOPT_COMPATIBLE"))
301 compatible=1;
302
303 if (argc == 1) {
304 if (compatible) {
305 /* For some reason, the original getopt gave no error
306 when there were no arguments. */
307 printf(" --\n");
308 return 0;
309 } else
310 bb_error_msg_and_die("missing optstring argument");
311 }
312
313 if (argv[1][0] != '-' || compatible) {
314 char *s;
315
316 quote=0;
317 s=xmalloc(strlen(argv[1])+1);
318 strcpy(s,argv[1]+strspn(argv[1],"-+"));
319 argv[1]=argv[0];
320 return generate_output(argv+1,argc-1,s,long_options);
321 }
322
323 while ((opt = getopt_long(argc,argv,shortopts,longopts,NULL)) != EOF)
324 switch (opt) {
325 case 'a':
326 alternative=1;
327 break;
328 case 'o':
329 optstr = optarg;
330 break;
331 case 'l':
332 add_long_options(optarg);
333 break;
334 case 'n':
335 name = optarg;
336 break;
337 case 'q':
338 quiet_errors=1;
339 break;
340 case 'Q':
341 quiet_output=1;
342 break;
343 case 's':
344 set_shell(optarg);
345 break;
346 case 'T':
347 return 4;
348 case 'u':
349 quote=0;
350 break;
351 default:
352 bb_show_usage();
353 }
354
355 if (!optstr) {
356 if (optind >= argc)
357 bb_error_msg_and_die("missing optstring argument");
358 else optstr=argv[optind++];
359 }
360 if (name)
361 argv[optind-1]=name;
362 else
363 argv[optind-1]=argv[0];
364 return generate_output(argv+optind-1,argc-optind+1,optstr,long_options);
365}
diff --git a/util-linux/hexdump.c b/util-linux/hexdump.c
new file mode 100644
index 000000000..5cb245feb
--- /dev/null
+++ b/util-linux/hexdump.c
@@ -0,0 +1,101 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * hexdump implementation for busybox
4 * Based on code from util-linux v 2.11l
5 *
6 * Copyright (c) 1989
7 * The Regents of the University of California. All rights reserved.
8 *
9 * Licensed under GPLv2 or later, see file License in this tarball for details.
10 */
11
12#include "busybox.h"
13#include <getopt.h>
14#include "dump.h"
15
16static void bb_dump_addfile(char *name)
17{
18 char *p;
19 FILE *fp;
20 char *buf;
21
22 fp = xfopen(name, "r");
23
24 while ((buf = xmalloc_getline(fp)) != NULL) {
25 p = skip_whitespace(buf);
26
27 if (*p && (*p != '#')) {
28 bb_dump_add(p);
29 }
30 free(buf);
31 }
32 fclose(fp);
33}
34
35static const char * const add_strings[] = {
36 "\"%07.7_ax \" 16/1 \"%03o \" \"\\n\"", /* b */
37 "\"%07.7_ax \" 16/1 \"%3_c \" \"\\n\"", /* c */
38 "\"%07.7_ax \" 8/2 \" %05u \" \"\\n\"", /* d */
39 "\"%07.7_ax \" 8/2 \" %06o \" \"\\n\"", /* o */
40 "\"%07.7_ax \" 8/2 \" %04x \" \"\\n\"", /* x */
41};
42
43static const char add_first[] = "\"%07.7_Ax\n\"";
44
45static const char hexdump_opts[] = "bcdoxCe:f:n:s:v";
46
47static const struct suffix_mult suffixes[] = {
48 {"b", 512 },
49 {"k", 1024 },
50 {"m", 1024*1024 },
51 {NULL, 0 }
52};
53
54int hexdump_main(int argc, char **argv)
55{
56 const char *p;
57 int ch;
58
59 bb_dump_vflag = FIRST;
60 bb_dump_length = -1;
61
62 while ((ch = getopt(argc, argv, hexdump_opts)) > 0) {
63 p = strchr(hexdump_opts, ch);
64 if (!p)
65 bb_show_usage();
66 if ((p - hexdump_opts) < 5) {
67 bb_dump_add(add_first);
68 bb_dump_add(add_strings[(int)(p - hexdump_opts)]);
69 } else if (ch == 'C') {
70 bb_dump_add("\"%08.8_Ax\n\"");
71 bb_dump_add("\"%08.8_ax \" 8/1 \"%02x \" \" \" 8/1 \"%02x \" ");
72 bb_dump_add("\" |\" 16/1 \"%_p\" \"|\\n\"");
73 } else {
74 /* Save a little bit of space below by omitting the 'else's. */
75 if (ch == 'e') {
76 bb_dump_add(optarg);
77 } /* else */
78 if (ch == 'f') {
79 bb_dump_addfile(optarg);
80 } /* else */
81 if (ch == 'n') {
82 bb_dump_length = xatoi_u(optarg);
83 } /* else */
84 if (ch == 's') {
85 bb_dump_skip = xatoul_range_sfx(optarg, 0, LONG_MAX, suffixes);
86 } /* else */
87 if (ch == 'v') {
88 bb_dump_vflag = ALL;
89 }
90 }
91 }
92
93 if (!bb_dump_fshead) {
94 bb_dump_add(add_first);
95 bb_dump_add("\"%07.7_ax \" 8/2 \"%04x \" \"\\n\"");
96 }
97
98 argv += optind;
99
100 return bb_dump_dump(argv);
101}
diff --git a/util-linux/hwclock.c b/util-linux/hwclock.c
new file mode 100644
index 000000000..8fcd8c99c
--- /dev/null
+++ b/util-linux/hwclock.c
@@ -0,0 +1,213 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini hwclock implementation for busybox
4 *
5 * Copyright (C) 2002 Robert Griebl <griebl@gmx.de>
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8*/
9
10
11#include <sys/ioctl.h>
12#include <sys/utsname.h>
13#include <getopt.h>
14#include "busybox.h"
15
16/* Copied from linux/rtc.h to eliminate the kernel dependency */
17struct linux_rtc_time {
18 int tm_sec;
19 int tm_min;
20 int tm_hour;
21 int tm_mday;
22 int tm_mon;
23 int tm_year;
24 int tm_wday;
25 int tm_yday;
26 int tm_isdst;
27};
28
29#define RTC_SET_TIME _IOW('p', 0x0a, struct linux_rtc_time) /* Set RTC time */
30#define RTC_RD_TIME _IOR('p', 0x09, struct linux_rtc_time) /* Read RTC time */
31
32#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
33# ifndef _GNU_SOURCE
34# define _GNU_SOURCE
35# endif
36#endif
37
38static int xopen_rtc(int flags)
39{
40 int rtc;
41 rtc = open("/dev/rtc", flags);
42 if (rtc < 0) {
43 rtc = open("/dev/misc/rtc", flags);
44 if (rtc < 0)
45 bb_perror_msg_and_die("cannot access RTC");
46 }
47 return rtc;
48}
49
50static time_t read_rtc(int utc)
51{
52 struct tm tm;
53 char *oldtz = 0;
54 time_t t = 0;
55 int rtc = xopen_rtc(O_RDONLY);
56
57 memset(&tm, 0, sizeof(struct tm));
58 if (ioctl(rtc, RTC_RD_TIME, &tm) < 0 )
59 bb_perror_msg_and_die("cannot read time from RTC");
60 tm.tm_isdst = -1; /* not known */
61
62 close(rtc);
63
64 if (utc) {
65 oldtz = getenv("TZ");
66 setenv("TZ", "UTC 0", 1);
67 tzset();
68 }
69
70 t = mktime(&tm);
71
72 if (utc) {
73 if (oldtz)
74 setenv("TZ", oldtz, 1);
75 else
76 unsetenv("TZ");
77 tzset();
78 }
79 return t;
80}
81
82static void write_rtc(time_t t, int utc)
83{
84 struct tm tm;
85 int rtc = xopen_rtc(O_WRONLY);
86
87 tm = *(utc ? gmtime(&t) : localtime(&t));
88 tm.tm_isdst = 0;
89
90 if (ioctl(rtc, RTC_SET_TIME, &tm) < 0)
91 bb_perror_msg_and_die("cannot set the RTC time");
92
93 close(rtc);
94}
95
96static int show_clock(int utc)
97{
98 struct tm *ptm;
99 time_t t;
100 RESERVE_CONFIG_BUFFER(buffer, 64);
101
102 t = read_rtc(utc);
103 ptm = localtime(&t); /* Sets 'tzname[]' */
104
105 safe_strncpy(buffer, ctime(&t), 64);
106 if (buffer[0])
107 buffer[strlen(buffer) - 1] = 0;
108
109 //printf("%s %.6f seconds %s\n", buffer, 0.0, utc ? "" : (ptm->tm_isdst ? tzname[1] : tzname[0]));
110 printf( "%s %.6f seconds\n", buffer, 0.0);
111 RELEASE_CONFIG_BUFFER(buffer);
112
113 return 0;
114}
115
116static int to_sys_clock(int utc)
117{
118 struct timeval tv = { 0, 0 };
119 const struct timezone tz = { timezone/60 - 60*daylight, 0 };
120
121 tv.tv_sec = read_rtc(utc);
122
123 if (settimeofday(&tv, &tz))
124 bb_perror_msg_and_die("settimeofday() failed");
125
126 return 0;
127}
128
129static int from_sys_clock(int utc)
130{
131 struct timeval tv = { 0, 0 };
132 struct timezone tz = { 0, 0 };
133
134 if (gettimeofday(&tv, &tz))
135 bb_perror_msg_and_die("gettimeofday() failed");
136
137 write_rtc(tv.tv_sec, utc);
138 return 0;
139}
140
141#ifdef CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS
142# define ADJTIME_PATH "/var/lib/hwclock/adjtime"
143#else
144# define ADJTIME_PATH "/etc/adjtime"
145#endif
146static int check_utc(void)
147{
148 int utc = 0;
149 FILE *f = fopen(ADJTIME_PATH, "r");
150
151 if (f) {
152 RESERVE_CONFIG_BUFFER(buffer, 128);
153
154 while (fgets(buffer, sizeof(buffer), f)) {
155 int len = strlen(buffer);
156
157 while (len && isspace(buffer[len - 1]))
158 len--;
159
160 buffer[len] = 0;
161
162 if (strncmp(buffer, "UTC", 3) == 0 ) {
163 utc = 1;
164 break;
165 }
166 }
167 fclose(f);
168 RELEASE_CONFIG_BUFFER(buffer);
169 }
170 return utc;
171}
172
173#define HWCLOCK_OPT_LOCALTIME 0x01
174#define HWCLOCK_OPT_UTC 0x02
175#define HWCLOCK_OPT_SHOW 0x04
176#define HWCLOCK_OPT_HCTOSYS 0x08
177#define HWCLOCK_OPT_SYSTOHC 0x10
178
179int hwclock_main(int argc, char **argv )
180{
181 unsigned opt;
182 int utc;
183
184#if ENABLE_FEATURE_HWCLOCK_LONG_OPTIONS
185 static const struct option hwclock_long_options[] = {
186 { "localtime", 0, 0, 'l' },
187 { "utc", 0, 0, 'u' },
188 { "show", 0, 0, 'r' },
189 { "hctosys", 0, 0, 's' },
190 { "systohc", 0, 0, 'w' },
191 { 0, 0, 0, 0 }
192 };
193 applet_long_options = hwclock_long_options;
194#endif
195 opt_complementary = "?:r--ws:w--rs:s--wr:l--u:u--l";
196 opt = getopt32(argc, argv, "lursw");
197
198 /* If -u or -l wasn't given check if we are using utc */
199 if (opt & (HWCLOCK_OPT_UTC | HWCLOCK_OPT_LOCALTIME))
200 utc = opt & HWCLOCK_OPT_UTC;
201 else
202 utc = check_utc();
203
204 if (opt & HWCLOCK_OPT_HCTOSYS) {
205 return to_sys_clock(utc);
206 }
207 else if (opt & HWCLOCK_OPT_SYSTOHC) {
208 return from_sys_clock(utc);
209 } else {
210 /* default HWCLOCK_OPT_SHOW */
211 return show_clock(utc);
212 }
213}
diff --git a/util-linux/ipcrm.c b/util-linux/ipcrm.c
new file mode 100644
index 000000000..507e58fe3
--- /dev/null
+++ b/util-linux/ipcrm.c
@@ -0,0 +1,217 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ipcrm.c - utility to allow removal of IPC objects and data structures.
4 *
5 * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com>
6 * Adapted for busybox from util-linux-2.12a.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include "busybox.h"
12
13/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
14/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
15#include <sys/ipc.h>
16#include <sys/shm.h>
17#include <sys/msg.h>
18#include <sys/sem.h>
19
20#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
21/* union semun is defined by including <sys/sem.h> */
22#else
23/* according to X/OPEN we have to define it ourselves */
24union semun {
25 int val;
26 struct semid_ds *buf;
27 unsigned short int *array;
28 struct seminfo *__buf;
29};
30#endif
31
32#ifndef CONFIG_IPCRM_DROP_LEGACY
33
34typedef enum type_id {
35 SHM,
36 SEM,
37 MSG
38} type_id;
39
40static int remove_ids(type_id type, int argc, char **argv)
41{
42 unsigned long id;
43 int ret = 0; /* silence gcc */
44 int nb_errors = 0;
45 union semun arg;
46
47 arg.val = 0;
48
49 while (argc) {
50 id = bb_strtoul(argv[0], NULL, 10);
51 if (errno || id > INT_MAX) {
52 bb_error_msg("invalid id: %s", argv[0]);
53 nb_errors++;
54 } else {
55 if (type == SEM)
56 ret = semctl(id, 0, IPC_RMID, arg);
57 else if (type == MSG)
58 ret = msgctl(id, IPC_RMID, NULL);
59 else if (type == SHM)
60 ret = shmctl(id, IPC_RMID, NULL);
61
62 if (ret) {
63 bb_perror_msg("cannot remove id %s", argv[0]);
64 nb_errors++;
65 }
66 }
67 argc--;
68 argv++;
69 }
70
71 return nb_errors;
72}
73#endif /* #ifndef CONFIG_IPCRM_DROP_LEGACY */
74
75
76int ipcrm_main(int argc, char **argv)
77{
78 int c;
79 int error = 0;
80
81 /* if the command is executed without parameters, do nothing */
82 if (argc == 1)
83 return 0;
84#ifndef CONFIG_IPCRM_DROP_LEGACY
85 /* check to see if the command is being invoked in the old way if so
86 then run the old code. Valid commands are msg, shm, sem. */
87 {
88 type_id what = 0; /* silence gcc */
89 char w;
90
91 w=argv[1][0];
92 if ( ((w == 'm' && argv[1][1] == 's' && argv[1][2] == 'g')
93 || (argv[1][0] == 's'
94 && ((w=argv[1][1]) == 'h' || w == 'e')
95 && argv[1][2] == 'm')
96 ) && argv[1][3] == '\0'
97 ) {
98
99 if (argc < 3)
100 bb_show_usage();
101
102 if (w == 'h')
103 what = SHM;
104 else if (w == 'm')
105 what = MSG;
106 else if (w == 'e')
107 what = SEM;
108
109 if (remove_ids(what, argc-2, &argv[2]))
110 fflush_stdout_and_exit(1);
111 printf("resource(s) deleted\n");
112 return 0;
113 }
114 }
115#endif /* #ifndef CONFIG_IPCRM_DROP_LEGACY */
116
117 /* process new syntax to conform with SYSV ipcrm */
118 while ((c = getopt(argc, argv, "q:m:s:Q:M:S:h?")) != -1) {
119 int result;
120 int id = 0;
121 int iskey = (isupper)(c);
122
123 /* needed to delete semaphores */
124 union semun arg;
125
126 arg.val = 0;
127
128 if ((c == '?') || (c == 'h')) {
129 bb_show_usage();
130 }
131
132 /* we don't need case information any more */
133 c = tolower(c);
134
135 /* make sure the option is in range: allowed are q, m, s */
136 if (c != 'q' && c != 'm' && c != 's') {
137 bb_show_usage();
138 }
139
140 if (iskey) {
141 /* keys are in hex or decimal */
142 key_t key = xstrtoul(optarg, 0);
143
144 if (key == IPC_PRIVATE) {
145 error++;
146 bb_error_msg("illegal key (%s)", optarg);
147 continue;
148 }
149
150 /* convert key to id */
151 id = ((c == 'q') ? msgget(key, 0) :
152 (c == 'm') ? shmget(key, 0, 0) : semget(key, 0, 0));
153
154 if (id < 0) {
155 char *errmsg;
156 const char * const what = "key";
157
158 error++;
159 switch (errno) {
160 case EACCES:
161 errmsg = "permission denied for";
162 break;
163 case EIDRM:
164 errmsg = "already removed";
165 break;
166 case ENOENT:
167 errmsg = "invalid";
168 break;
169 default:
170 errmsg = "unknown error in";
171 break;
172 }
173 bb_error_msg("%s %s (%s)", errmsg, what, optarg);
174 continue;
175 }
176 } else {
177 /* ids are in decimal */
178 id = xatoul(optarg);
179 }
180
181 result = ((c == 'q') ? msgctl(id, IPC_RMID, NULL) :
182 (c == 'm') ? shmctl(id, IPC_RMID, NULL) :
183 semctl(id, 0, IPC_RMID, arg));
184
185 if (result) {
186 char *errmsg;
187 const char * const what = iskey ? "key" : "id";
188
189 error++;
190 switch (errno) {
191 case EACCES:
192 case EPERM:
193 errmsg = "permission denied for";
194 break;
195 case EINVAL:
196 errmsg = "invalid";
197 break;
198 case EIDRM:
199 errmsg = "already removed";
200 break;
201 default:
202 errmsg = "unknown error in";
203 break;
204 }
205 bb_error_msg("%s %s (%s)", errmsg, what, optarg);
206 continue;
207 }
208 }
209
210 /* print usage if we still have some arguments left over */
211 if (optind != argc) {
212 bb_show_usage();
213 }
214
215 /* exit value reflects the number of errors encountered */
216 return error;
217}
diff --git a/util-linux/ipcs.c b/util-linux/ipcs.c
new file mode 100644
index 000000000..b81d07d6d
--- /dev/null
+++ b/util-linux/ipcs.c
@@ -0,0 +1,630 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * ipcs.c -- provides information on allocated ipc resources.
4 *
5 * 01 Sept 2004 - Rodney Radford <rradford@mindspring.com>
6 * Adapted for busybox from util-linux-2.12a.
7 *
8 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
9 */
10
11#include "busybox.h"
12#include <errno.h>
13#include <time.h>
14#include <pwd.h>
15#include <grp.h>
16
17/* X/OPEN tells us to use <sys/{types,ipc,sem}.h> for semctl() */
18/* X/OPEN tells us to use <sys/{types,ipc,msg}.h> for msgctl() */
19/* X/OPEN tells us to use <sys/{types,ipc,shm}.h> for shmctl() */
20#include <sys/types.h>
21#include <sys/ipc.h>
22#include <sys/sem.h>
23#include <sys/msg.h>
24#include <sys/shm.h>
25
26
27
28/*-------------------------------------------------------------------*/
29/* SHM_DEST and SHM_LOCKED are defined in kernel headers,
30 but inside #ifdef __KERNEL__ ... #endif */
31#ifndef SHM_DEST
32/* shm_mode upper byte flags */
33#define SHM_DEST 01000 /* segment will be destroyed on last detach */
34#define SHM_LOCKED 02000 /* segment will not be swapped */
35#endif
36
37/* For older kernels the same holds for the defines below */
38#ifndef MSG_STAT
39#define MSG_STAT 11
40#define MSG_INFO 12
41#endif
42
43#ifndef SHM_STAT
44#define SHM_STAT 13
45#define SHM_INFO 14
46struct shm_info {
47 int used_ids;
48 ulong shm_tot; /* total allocated shm */
49 ulong shm_rss; /* total resident shm */
50 ulong shm_swp; /* total swapped shm */
51 ulong swap_attempts;
52 ulong swap_successes;
53};
54#endif
55
56#ifndef SEM_STAT
57#define SEM_STAT 18
58#define SEM_INFO 19
59#endif
60
61/* Some versions of libc only define IPC_INFO when __USE_GNU is defined. */
62#ifndef IPC_INFO
63#define IPC_INFO 3
64#endif
65/*-------------------------------------------------------------------*/
66
67/* The last arg of semctl is a union semun, but where is it defined?
68 X/OPEN tells us to define it ourselves, but until recently
69 Linux include files would also define it. */
70#if defined (__GNU_LIBRARY__) && !defined(_SEM_SEMUN_UNDEFINED)
71/* union semun is defined by including <sys/sem.h> */
72#else
73/* according to X/OPEN we have to define it ourselves */
74union semun {
75 int val;
76 struct semid_ds *buf;
77 unsigned short int *array;
78 struct seminfo *__buf;
79};
80#endif
81
82/* X/OPEN (Jan 1987) does not define fields key, seq in struct ipc_perm;
83 libc 4/5 does not mention struct ipc_term at all, but includes
84 <linux/ipc.h>, which defines a struct ipc_perm with such fields.
85 glibc-1.09 has no support for sysv ipc.
86 glibc 2 uses __key, __seq */
87#if defined (__GNU_LIBRARY__) && __GNU_LIBRARY__ > 1
88#define KEY __key
89#else
90#define KEY key
91#endif
92
93#define LIMITS 1
94#define STATUS 2
95#define CREATOR 3
96#define TIME 4
97#define PID 5
98
99static char format;
100
101static void print_perms(int id, struct ipc_perm *ipcp)
102{
103 struct passwd *pw;
104 struct group *gr;
105
106 printf("%-10d %-10o", id, ipcp->mode & 0777);
107
108 if ((pw = getpwuid(ipcp->cuid)))
109 printf(" %-10s", pw->pw_name);
110 else
111 printf(" %-10d", ipcp->cuid);
112 if ((gr = getgrgid(ipcp->cgid)))
113 printf(" %-10s", gr->gr_name);
114 else
115 printf(" %-10d", ipcp->cgid);
116
117 if ((pw = getpwuid(ipcp->uid)))
118 printf(" %-10s", pw->pw_name);
119 else
120 printf(" %-10d", ipcp->uid);
121 if ((gr = getgrgid(ipcp->gid)))
122 printf(" %-10s\n", gr->gr_name);
123 else
124 printf(" %-10d\n", ipcp->gid);
125}
126
127
128static void do_shm(void)
129{
130 int maxid, shmid, id;
131 struct shmid_ds shmseg;
132 struct shm_info shm_info;
133 struct shminfo shminfo;
134 struct ipc_perm *ipcp = &shmseg.shm_perm;
135 struct passwd *pw;
136
137 maxid = shmctl(0, SHM_INFO, (struct shmid_ds *) (void *) &shm_info);
138 if (maxid < 0) {
139 printf("kernel not configured for %s\n", "shared memory");
140 return;
141 }
142
143 switch (format) {
144 case LIMITS:
145 printf("------ Shared Memory %s --------\n", "Limits");
146 if ((shmctl(0, IPC_INFO, (struct shmid_ds *) (void *) &shminfo)) < 0)
147 return;
148 /* glibc 2.1.3 and all earlier libc's have ints as fields
149 of struct shminfo; glibc 2.1.91 has unsigned long; ach */
150 printf("max number of segments = %lu\n"
151 "max seg size (kbytes) = %lu\n"
152 "max total shared memory (pages) = %lu\n"
153 "min seg size (bytes) = %lu\n",
154 (unsigned long) shminfo.shmmni,
155 (unsigned long) (shminfo.shmmax >> 10),
156 (unsigned long) shminfo.shmall,
157 (unsigned long) shminfo.shmmin);
158 return;
159
160 case STATUS:
161 printf("------ Shared Memory %s --------\n", "Status");
162 printf( "segments allocated %d\n"
163 "pages allocated %ld\n"
164 "pages resident %ld\n"
165 "pages swapped %ld\n"
166 "Swap performance: %ld attempts\t%ld successes\n",
167 shm_info.used_ids,
168 shm_info.shm_tot,
169 shm_info.shm_rss,
170 shm_info.shm_swp,
171 shm_info.swap_attempts, shm_info.swap_successes);
172 return;
173
174 case CREATOR:
175 printf("------ Shared Memory %s --------\n", "Segment Creators/Owners");
176 printf( "%-10s %-10s %-10s %-10s %-10s %-10s\n",
177 "shmid", "perms", "cuid", "cgid", "uid", "gid");
178 break;
179
180 case TIME:
181 printf("------ Shared Memory %s --------\n", "Attach/Detach/Change Times");
182 printf( "%-10s %-10s %-20s %-20s %-20s\n",
183 "shmid", "owner", "attached", "detached", "changed");
184 break;
185
186 case PID:
187 printf("------ Shared Memory %s --------\n", "Creator/Last-op");
188 printf( "%-10s %-10s %-10s %-10s\n",
189 "shmid", "owner", "cpid", "lpid");
190 break;
191
192 default:
193 printf("------ Shared Memory %s --------\n", "Segments");
194 printf( "%-10s %-10s %-10s %-10s %-10s %-10s %-12s\n",
195 "key", "shmid", "owner", "perms", "bytes", "nattch",
196 "status");
197 break;
198 }
199
200 for (id = 0; id <= maxid; id++) {
201 shmid = shmctl(id, SHM_STAT, &shmseg);
202 if (shmid < 0)
203 continue;
204 if (format == CREATOR) {
205 print_perms(shmid, ipcp);
206 continue;
207 }
208 pw = getpwuid(ipcp->uid);
209 switch (format) {
210 case TIME:
211 if (pw)
212 printf("%-10d %-10.10s", shmid, pw->pw_name);
213 else
214 printf("%-10d %-10d", shmid, ipcp->uid);
215 /* ctime uses static buffer: use separate calls */
216 printf(" %-20.16s", shmseg.shm_atime
217 ? ctime(&shmseg.shm_atime) + 4 : "Not set");
218 printf(" %-20.16s", shmseg.shm_dtime
219 ? ctime(&shmseg.shm_dtime) + 4 : "Not set");
220 printf(" %-20.16s\n", shmseg.shm_ctime
221 ? ctime(&shmseg.shm_ctime) + 4 : "Not set");
222 break;
223 case PID:
224 if (pw)
225 printf("%-10d %-10.10s", shmid, pw->pw_name);
226 else
227 printf("%-10d %-10d", shmid, ipcp->uid);
228 printf(" %-10d %-10d\n", shmseg.shm_cpid, shmseg.shm_lpid);
229 break;
230
231 default:
232 printf("0x%08x ", ipcp->KEY);
233 if (pw)
234 printf("%-10d %-10.10s", shmid, pw->pw_name);
235 else
236 printf("%-10d %-10d", shmid, ipcp->uid);
237 printf(" %-10o %-10lu %-10ld %-6s %-6s\n", ipcp->mode & 0777,
238 /*
239 * earlier: int, Austin has size_t
240 */
241 (unsigned long) shmseg.shm_segsz,
242 /*
243 * glibc-2.1.3 and earlier has unsigned short;
244 * Austin has shmatt_t
245 */
246 (long) shmseg.shm_nattch,
247 ipcp->mode & SHM_DEST ? "dest" : " ",
248 ipcp->mode & SHM_LOCKED ? "locked" : " ");
249 break;
250 }
251 }
252}
253
254
255static void do_sem(void)
256{
257 int maxid, semid, id;
258 struct semid_ds semary;
259 struct seminfo seminfo;
260 struct ipc_perm *ipcp = &semary.sem_perm;
261 struct passwd *pw;
262 union semun arg;
263
264 arg.array = (ushort *) (void *) &seminfo;
265 maxid = semctl(0, 0, SEM_INFO, arg);
266 if (maxid < 0) {
267 printf("kernel not configured for %s\n", "semaphores");
268 return;
269 }
270
271 switch (format) {
272 case LIMITS:
273 printf("------ Semaphore %s --------\n", "Limits");
274 arg.array = (ushort *) (void *) &seminfo; /* damn union */
275 if ((semctl(0, 0, IPC_INFO, arg)) < 0)
276 return;
277 printf("max number of arrays = %d\n"
278 "max semaphores per array = %d\n"
279 "max semaphores system wide = %d\n"
280 "max ops per semop call = %d\n"
281 "semaphore max value = %d\n",
282 seminfo.semmni,
283 seminfo.semmsl,
284 seminfo.semmns, seminfo.semopm, seminfo.semvmx);
285 return;
286
287 case STATUS:
288 printf("------ Semaphore %s --------\n", "Status");
289 printf( "used arrays = %d\n"
290 "allocated semaphores = %d\n",
291 seminfo.semusz, seminfo.semaem);
292 return;
293
294 case CREATOR:
295 printf("------ Semaphore %s --------\n", "Arrays Creators/Owners");
296 printf( "%-10s %-10s %-10s %-10s %-10s %-10s\n",
297 "semid", "perms", "cuid", "cgid", "uid", "gid");
298 break;
299
300 case TIME:
301 printf("------ Shared Memory %s --------\n", "Operation/Change Times");
302 printf( "%-8s %-10s %-26.24s %-26.24s\n",
303 "shmid", "owner", "last-op", "last-changed");
304 break;
305
306 case PID:
307 break;
308
309 default:
310 printf("------ Semaphore %s --------\n", "Arrays");
311 printf( "%-10s %-10s %-10s %-10s %-10s\n",
312 "key", "semid", "owner", "perms", "nsems");
313 break;
314 }
315
316 for (id = 0; id <= maxid; id++) {
317 arg.buf = (struct semid_ds *) &semary;
318 semid = semctl(id, 0, SEM_STAT, arg);
319 if (semid < 0)
320 continue;
321 if (format == CREATOR) {
322 print_perms(semid, ipcp);
323 continue;
324 }
325 pw = getpwuid(ipcp->uid);
326 switch (format) {
327 case TIME:
328 if (pw)
329 printf("%-8d %-10.10s", semid, pw->pw_name);
330 else
331 printf("%-8d %-10d", semid, ipcp->uid);
332 /* ctime uses static buffer: use separate calls */
333 printf(" %-26.24s", semary.sem_otime
334 ? ctime(&semary.sem_otime) : "Not set");
335 printf(" %-26.24s\n", semary.sem_ctime
336 ? ctime(&semary.sem_ctime) : "Not set");
337 break;
338 case PID:
339 break;
340
341 default:
342 printf("0x%08x ", ipcp->KEY);
343 if (pw)
344 printf("%-10d %-10.9s", semid, pw->pw_name);
345 else
346 printf("%-10d %-9d", semid, ipcp->uid);
347 printf(" %-10o %-10ld\n", ipcp->mode & 0777,
348 /*
349 * glibc-2.1.3 and earlier has unsigned short;
350 * glibc-2.1.91 has variation between
351 * unsigned short and unsigned long
352 * Austin prescribes unsigned short.
353 */
354 (long) semary.sem_nsems);
355 break;
356 }
357 }
358}
359
360
361static void do_msg(void)
362{
363 int maxid, msqid, id;
364 struct msqid_ds msgque;
365 struct msginfo msginfo;
366 struct ipc_perm *ipcp = &msgque.msg_perm;
367 struct passwd *pw;
368
369 maxid = msgctl(0, MSG_INFO, (struct msqid_ds *) (void *) &msginfo);
370 if (maxid < 0) {
371 printf("kernel not configured for %s\n", "message queues");
372 return;
373 }
374
375 switch (format) {
376 case LIMITS:
377 if ((msgctl(0, IPC_INFO, (struct msqid_ds *) (void *) &msginfo)) < 0)
378 return;
379 printf("------ Message%s --------\n", "s: Limits");
380 printf( "max queues system wide = %d\n"
381 "max size of message (bytes) = %d\n"
382 "default max size of queue (bytes) = %d\n",
383 msginfo.msgmni, msginfo.msgmax, msginfo.msgmnb);
384 return;
385
386 case STATUS:
387 printf("------ Message%s --------\n", "s: Status");
388 printf( "allocated queues = %d\n"
389 "used headers = %d\n"
390 "used space = %d bytes\n",
391 msginfo.msgpool, msginfo.msgmap, msginfo.msgtql);
392 return;
393
394 case CREATOR:
395 printf("------ Message%s --------\n", " Queues: Creators/Owners");
396 printf( "%-10s %-10s %-10s %-10s %-10s %-10s\n",
397 "msqid", "perms", "cuid", "cgid", "uid", "gid");
398 break;
399
400 case TIME:
401 printf("------ Message%s --------\n", " Queues Send/Recv/Change Times");
402 printf( "%-8s %-10s %-20s %-20s %-20s\n",
403 "msqid", "owner", "send", "recv", "change");
404 break;
405
406 case PID:
407 printf("------ Message%s --------\n", " Queues PIDs");
408 printf( "%-10s %-10s %-10s %-10s\n",
409 "msqid", "owner", "lspid", "lrpid");
410 break;
411
412 default:
413 printf("------ Message%s --------\n", " Queues");
414 printf( "%-10s %-10s %-10s %-10s %-12s %-12s\n",
415 "key", "msqid", "owner", "perms", "used-bytes", "messages");
416 break;
417 }
418
419 for (id = 0; id <= maxid; id++) {
420 msqid = msgctl(id, MSG_STAT, &msgque);
421 if (msqid < 0)
422 continue;
423 if (format == CREATOR) {
424 print_perms(msqid, ipcp);
425 continue;
426 }
427 pw = getpwuid(ipcp->uid);
428 switch (format) {
429 case TIME:
430 if (pw)
431 printf("%-8d %-10.10s", msqid, pw->pw_name);
432 else
433 printf("%-8d %-10d", msqid, ipcp->uid);
434 printf(" %-20.16s", msgque.msg_stime
435 ? ctime(&msgque.msg_stime) + 4 : "Not set");
436 printf(" %-20.16s", msgque.msg_rtime
437 ? ctime(&msgque.msg_rtime) + 4 : "Not set");
438 printf(" %-20.16s\n", msgque.msg_ctime
439 ? ctime(&msgque.msg_ctime) + 4 : "Not set");
440 break;
441 case PID:
442 if (pw)
443 printf("%-8d %-10.10s", msqid, pw->pw_name);
444 else
445 printf("%-8d %-10d", msqid, ipcp->uid);
446 printf(" %5d %5d\n", msgque.msg_lspid, msgque.msg_lrpid);
447 break;
448
449 default:
450 printf("0x%08x ", ipcp->KEY);
451 if (pw)
452 printf("%-10d %-10.10s", msqid, pw->pw_name);
453 else
454 printf("%-10d %-10d", msqid, ipcp->uid);
455 printf(" %-10o %-12ld %-12ld\n", ipcp->mode & 0777,
456 /*
457 * glibc-2.1.3 and earlier has unsigned short;
458 * glibc-2.1.91 has variation between
459 * unsigned short, unsigned long
460 * Austin has msgqnum_t
461 */
462 (long) msgque.msg_cbytes, (long) msgque.msg_qnum);
463 break;
464 }
465 }
466}
467
468
469static void print_shm(int shmid)
470{
471 struct shmid_ds shmds;
472 struct ipc_perm *ipcp = &shmds.shm_perm;
473
474 if (shmctl(shmid, IPC_STAT, &shmds) == -1) {
475 bb_perror_msg("shmctl");
476 return;
477 }
478
479 printf("\nShared memory Segment shmid=%d\n"
480 "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\n"
481 "mode=%#o\taccess_perms=%#o\n"
482 "bytes=%ld\tlpid=%d\tcpid=%d\tnattch=%ld\n",
483 shmid,
484 ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid,
485 ipcp->mode, ipcp->mode & 0777,
486 (long) shmds.shm_segsz, shmds.shm_lpid, shmds.shm_cpid,
487 (long) shmds.shm_nattch);
488 printf("att_time=%-26.24s\n",
489 shmds.shm_atime ? ctime(&shmds.shm_atime) : "Not set");
490 printf("det_time=%-26.24s\n",
491 shmds.shm_dtime ? ctime(&shmds.shm_dtime) : "Not set");
492 printf("change_time=%-26.24s\n\n", ctime(&shmds.shm_ctime));
493}
494
495
496static void print_msg(int msqid)
497{
498 struct msqid_ds buf;
499 struct ipc_perm *ipcp = &buf.msg_perm;
500
501 if (msgctl(msqid, IPC_STAT, &buf) == -1) {
502 bb_perror_msg("msgctl");
503 return;
504 }
505
506 printf("\nMessage Queue msqid=%d\n"
507 "uid=%d\tgid=%d\tcuid=%d\tcgid=%d\tmode=%#o\n"
508 "cbytes=%ld\tqbytes=%ld\tqnum=%ld\tlspid=%d\tlrpid=%d\n",
509 msqid, ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid, ipcp->mode,
510 /*
511 * glibc-2.1.3 and earlier has unsigned short;
512 * glibc-2.1.91 has variation between
513 * unsigned short, unsigned long
514 * Austin has msgqnum_t (for msg_qbytes)
515 */
516 (long) buf.msg_cbytes, (long) buf.msg_qbytes,
517 (long) buf.msg_qnum, buf.msg_lspid, buf.msg_lrpid);
518
519 printf("send_time=%-26.24s\n",
520 buf.msg_stime ? ctime(&buf.msg_stime) : "Not set");
521 printf("rcv_time=%-26.24s\n",
522 buf.msg_rtime ? ctime(&buf.msg_rtime) : "Not set");
523 printf("change_time=%-26.24s\n\n",
524 buf.msg_ctime ? ctime(&buf.msg_ctime) : "Not set");
525}
526
527static void print_sem(int semid)
528{
529 struct semid_ds semds;
530 struct ipc_perm *ipcp = &semds.sem_perm;
531 union semun arg;
532 unsigned int i;
533
534 arg.buf = &semds;
535 if (semctl(semid, 0, IPC_STAT, arg)) {
536 bb_perror_msg("semctl");
537 return;
538 }
539
540 printf("\nSemaphore Array semid=%d\n"
541 "uid=%d\t gid=%d\t cuid=%d\t cgid=%d\n"
542 "mode=%#o, access_perms=%#o\n"
543 "nsems = %ld\n"
544 "otime = %-26.24s\n",
545 semid,
546 ipcp->uid, ipcp->gid, ipcp->cuid, ipcp->cgid,
547 ipcp->mode, ipcp->mode & 0777,
548 (long) semds.sem_nsems,
549 semds.sem_otime ? ctime(&semds.sem_otime) : "Not set");
550 printf("ctime = %-26.24s\n"
551 "%-10s %-10s %-10s %-10s %-10s\n",
552 ctime(&semds.sem_ctime),
553 "semnum", "value", "ncount", "zcount", "pid");
554
555 arg.val = 0;
556 for (i = 0; i < semds.sem_nsems; i++) {
557 int val, ncnt, zcnt, pid;
558
559 val = semctl(semid, i, GETVAL, arg);
560 ncnt = semctl(semid, i, GETNCNT, arg);
561 zcnt = semctl(semid, i, GETZCNT, arg);
562 pid = semctl(semid, i, GETPID, arg);
563 if (val < 0 || ncnt < 0 || zcnt < 0 || pid < 0) {
564 bb_perror_msg_and_die("semctl");
565 }
566 printf("%-10d %-10d %-10d %-10d %-10d\n", i, val, ncnt, zcnt, pid);
567 }
568 puts("");
569}
570
571int ipcs_main(int argc, char **argv)
572{
573 int id = 0;
574 unsigned flags = 0;
575 unsigned opt;
576 char *opt_i;
577#define flag_print (1<<0)
578#define flag_msg (1<<1)
579#define flag_sem (1<<2)
580#define flag_shm (1<<3)
581
582 opt = getopt32(argc, argv, "i:aqsmtcplu", &opt_i);
583 if (opt & 0x1) { // -i
584 id = xatoi(opt_i);
585 flags |= flag_print;
586 }
587 if (opt & 0x2) flags |= flag_msg | flag_sem | flag_shm; // -a
588 if (opt & 0x4) flags |= flag_msg; // -q
589 if (opt & 0x8) flags |= flag_sem; // -s
590 if (opt & 0x10) flags |= flag_shm; // -m
591 if (opt & 0x20) format = TIME; // -t
592 if (opt & 0x40) format = CREATOR; // -c
593 if (opt & 0x80) format = PID; // -p
594 if (opt & 0x100) format = LIMITS; // -l
595 if (opt & 0x200) format = STATUS; // -u
596
597 if (flags & flag_print) {
598 if (flags & flag_shm) {
599 print_shm(id);
600 fflush_stdout_and_exit(0);
601 }
602 if (flags & flag_sem) {
603 print_sem(id);
604 fflush_stdout_and_exit(0);
605 }
606 if (flags & flag_msg) {
607 print_msg(id);
608 fflush_stdout_and_exit(0);
609 }
610 bb_show_usage();
611 }
612
613 if (!(flags & (flag_shm | flag_msg | flag_sem)))
614 flags |= flag_msg | flag_shm | flag_sem;
615 puts("");
616
617 if (flags & flag_shm) {
618 do_shm();
619 puts("");
620 }
621 if (flags & flag_sem) {
622 do_sem();
623 puts("");
624 }
625 if (flags & flag_msg) {
626 do_msg();
627 puts("");
628 }
629 fflush_stdout_and_exit(0);
630}
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
new file mode 100644
index 000000000..c7eb85a91
--- /dev/null
+++ b/util-linux/losetup.c
@@ -0,0 +1,64 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini losetup implementation for busybox
4 *
5 * Copyright (C) 2002 Matt Kraai.
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10#include <getopt.h>
11#include <stdlib.h>
12
13#include "busybox.h"
14
15int losetup_main(int argc, char **argv)
16{
17 unsigned opt;
18 char *opt_o;
19 unsigned long long offset = 0;
20
21 opt = getopt32(argc, argv, "do:", &opt_o);
22 argc -= optind;
23 argv += optind;
24
25 if (opt == 0x3) // -d + -o (illegal)
26 bb_show_usage();
27
28 if (opt == 0x1) { // -d
29 /* detach takes exactly one argument */
30 if (argc != 1)
31 bb_show_usage();
32 if (!del_loop(argv[0]))
33 return EXIT_SUCCESS;
34 bb_perror_nomsg_and_die();
35 }
36
37 if (opt == 0x2) // -o
38 offset = xatoull(opt_o);
39
40 /* -o or no option */
41
42 if (argc == 2) {
43 if (set_loop(&argv[0], argv[1], offset) < 0)
44 bb_perror_nomsg_and_die();
45 } else if (argc == 1) {
46 char *s = query_loop(argv[0]);
47 if (!s) bb_perror_nomsg_and_die();
48 printf("%s: %s\n", argv[0], s);
49 if (ENABLE_FEATURE_CLEAN_UP) free(s);
50 } else {
51 char dev[sizeof(LOOP_NAME"0")] = LOOP_NAME"0";
52 char c;
53 for (c = '0'; c <= '9'; ++c) {
54 char *s;
55 dev[sizeof(LOOP_NAME"0")-2] = c;
56 s = query_loop(dev);
57 if (s) {
58 printf("%s: %s\n", dev, s);
59 if (ENABLE_FEATURE_CLEAN_UP) free(s);
60 }
61 }
62 }
63 return EXIT_SUCCESS;
64}
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
new file mode 100644
index 000000000..957316d52
--- /dev/null
+++ b/util-linux/mdev.c
@@ -0,0 +1,268 @@
1/* vi: set sw=4 ts=4: */
2/*
3 *
4 * mdev - Mini udev for busybox
5 *
6 * Copyright 2005 Rob Landley <rob@landley.net>
7 * Copyright 2005 Frank Sorenson <frank@tuxrocks.com>
8 *
9 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
10 */
11
12#include "busybox.h"
13#include "xregex.h"
14
15#define DEV_PATH "/dev"
16
17struct mdev_globals
18{
19 int root_major, root_minor;
20} mdev_globals;
21
22#define bbg mdev_globals
23
24/* mknod in /dev based on a path like "/sys/block/hda/hda1" */
25static void make_device(char *path, int delete)
26{
27 char *device_name;
28 int major, minor, type, len;
29 int mode = 0660;
30 uid_t uid = 0;
31 gid_t gid = 0;
32 char *temp = path + strlen(path);
33 char *command = NULL;
34
35 /* Try to read major/minor string. Note that the kernel puts \n after
36 * the data, so we don't need to worry about null terminating the string
37 * because sscanf() will stop at the first nondigit, which \n is. We
38 * also depend on path having writeable space after it. */
39
40 if (!delete) {
41 strcat(path, "/dev");
42 len = open_read_close(path, temp + 1, 64);
43 *temp++ = 0;
44 if (len < 1) return;
45 }
46
47 /* Determine device name, type, major and minor */
48
49 device_name = strrchr(path, '/') + 1;
50 type = path[5]=='c' ? S_IFCHR : S_IFBLK;
51
52 /* If we have a config file, look up permissions for this device */
53
54 if (ENABLE_FEATURE_MDEV_CONF) {
55 char *conf, *pos, *end;
56 int line, fd;
57
58 /* mmap the config file */
59 fd = open("/etc/mdev.conf", O_RDONLY);
60 if (fd < 0)
61 goto end_parse;
62 len = xlseek(fd, 0, SEEK_END);
63 conf = mmap(NULL, len, PROT_READ, MAP_PRIVATE, fd, 0);
64 close(fd);
65 if (!conf)
66 goto end_parse;
67
68 line = 0;
69 /* Loop through lines in mmaped file*/
70 for (pos=conf; pos-conf<len;) {
71 int field;
72 char *end2;
73
74 line++;
75 /* find end of this line */
76 for (end=pos; end-conf<len && *end!='\n'; end++)
77 ;
78
79 /* Three fields: regex, uid:gid, mode */
80 for (field=0; field < (3 + ENABLE_FEATURE_MDEV_EXEC);
81 field++)
82 {
83 /* Skip whitespace */
84 while (pos<end && isspace(*pos)) pos++;
85 if (pos==end || *pos=='#') break;
86 for (end2=pos;
87 end2<end && !isspace(*end2) && *end2!='#'; end2++)
88 ;
89
90 if (field == 0) {
91 /* Regex to match this device */
92
93 char *regex = strndupa(pos, end2-pos);
94 regex_t match;
95 regmatch_t off;
96 int result;
97
98 /* Is this it? */
99 xregcomp(&match,regex, REG_EXTENDED);
100 result = regexec(&match, device_name, 1, &off, 0);
101 regfree(&match);
102
103 /* If not this device, skip rest of line */
104 if (result || off.rm_so
105 || off.rm_eo != strlen(device_name))
106 break;
107 }
108 if (field == 1) {
109 /* uid:gid */
110
111 char *s, *s2;
112
113 /* Find : */
114 for (s=pos; s<end2 && *s!=':'; s++)
115 ;
116 if (s == end2) break;
117
118 /* Parse UID */
119 uid = strtoul(pos, &s2, 10);
120 if (s != s2) {
121 struct passwd *pass;
122 pass = getpwnam(strndupa(pos, s-pos));
123 if (!pass) break;
124 uid = pass->pw_uid;
125 }
126 s++;
127 /* parse GID */
128 gid = strtoul(s, &s2, 10);
129 if (end2 != s2) {
130 struct group *grp;
131 grp = getgrnam(strndupa(s, end2-s));
132 if (!grp) break;
133 gid = grp->gr_gid;
134 }
135 }
136 if (field == 2) {
137 /* mode */
138
139 mode = strtoul(pos, &pos, 8);
140 if (pos != end2) break;
141 }
142 if (ENABLE_FEATURE_MDEV_EXEC && field == 3) {
143 // Command to run
144 char *s = "@$*", *s2;
145 s2 = strchr(s, *pos++);
146 if (!s2) {
147 // Force error
148 field = 1;
149 break;
150 }
151 if ((s2-s+1) & (1<<delete))
152 command = xstrndup(pos, end-pos);
153 }
154
155 pos = end2;
156 }
157
158 /* Did everything parse happily? */
159
160 if (field > 2) break;
161 if (field) bb_error_msg_and_die("bad line %d",line);
162
163 /* Next line */
164 pos = ++end;
165 }
166 munmap(conf, len);
167 end_parse: /* nothing */ ;
168 }
169
170 umask(0);
171 if (!delete) {
172 if (sscanf(temp, "%d:%d", &major, &minor) != 2) return;
173 if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST)
174 bb_perror_msg_and_die("mknod %s", device_name);
175
176 if (major == bbg.root_major && minor == bbg.root_minor)
177 symlink(device_name, "root");
178
179 if (ENABLE_FEATURE_MDEV_CONF) chown(device_name, uid, gid);
180 }
181 if (command) {
182 int rc;
183 char *s;
184
185 s = xasprintf("MDEV=%s", device_name);
186 putenv(s);
187 rc = system(command);
188 s[4] = 0;
189 putenv(s);
190 free(s);
191 free(command);
192 if (rc == -1) bb_perror_msg_and_die("cannot run %s", command);
193 }
194 if (delete) unlink(device_name);
195}
196
197/* Recursive search of /sys/block or /sys/class. path must be a writeable
198 * buffer of size PATH_MAX containing the directory string to start at. */
199
200static void find_dev(char *path)
201{
202 DIR *dir;
203 size_t len = strlen(path);
204 struct dirent *entry;
205
206 dir = opendir(path);
207 if (dir == NULL)
208 return;
209
210 while ((entry = readdir(dir)) != NULL) {
211 struct stat st;
212
213 /* Skip "." and ".." (also skips hidden files, which is ok) */
214
215 if (entry->d_name[0] == '.')
216 continue;
217
218 // uClibc doesn't fill out entry->d_type reliably. so we use lstat().
219
220 snprintf(path+len, PATH_MAX-len, "/%s", entry->d_name);
221 if (!lstat(path, &st) && S_ISDIR(st.st_mode)) find_dev(path);
222 path[len] = 0;
223
224 /* If there's a dev entry, mknod it */
225
226 if (!strcmp(entry->d_name, "dev")) make_device(path, 0);
227 }
228
229 closedir(dir);
230}
231
232int mdev_main(int argc, char *argv[])
233{
234 char *action;
235 char *env_path;
236 RESERVE_CONFIG_BUFFER(temp,PATH_MAX);
237
238 xchdir(DEV_PATH);
239
240 /* Scan */
241
242 if (argc == 2 && !strcmp(argv[1],"-s")) {
243 struct stat st;
244
245 xstat("/", &st);
246 bbg.root_major = major(st.st_dev);
247 bbg.root_minor = minor(st.st_dev);
248 strcpy(temp,"/sys/block");
249 find_dev(temp);
250 strcpy(temp,"/sys/class");
251 find_dev(temp);
252
253 /* Hotplug */
254
255 } else {
256 action = getenv("ACTION");
257 env_path = getenv("DEVPATH");
258 if (!action || !env_path)
259 bb_show_usage();
260
261 sprintf(temp, "/sys%s", env_path);
262 if (!strcmp(action, "add")) make_device(temp,0);
263 else if (!strcmp(action, "remove")) make_device(temp,1);
264 }
265
266 if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp);
267 return 0;
268}
diff --git a/util-linux/mkfs_minix.c b/util-linux/mkfs_minix.c
new file mode 100644
index 000000000..af19da68c
--- /dev/null
+++ b/util-linux/mkfs_minix.c
@@ -0,0 +1,762 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * mkfs.c - make a linux (minix) file-system.
4 *
5 * (C) 1991 Linus Torvalds. This file may be redistributed as per
6 * the Linux copyright.
7 */
8
9/*
10 * DD.MM.YY
11 *
12 * 24.11.91 - Time began. Used the fsck sources to get started.
13 *
14 * 25.11.91 - Corrected some bugs. Added support for ".badblocks"
15 * The algorithm for ".badblocks" is a bit weird, but
16 * it should work. Oh, well.
17 *
18 * 25.01.92 - Added the -l option for getting the list of bad blocks
19 * out of a named file. (Dave Rivers, rivers@ponds.uucp)
20 *
21 * 28.02.92 - Added %-information when using -c.
22 *
23 * 28.02.93 - Added support for other namelengths than the original
24 * 14 characters so that I can test the new kernel routines..
25 *
26 * 09.10.93 - Make exit status conform to that required by fsutil
27 * (Rik Faith, faith@cs.unc.edu)
28 *
29 * 31.10.93 - Added inode request feature, for backup floppies: use
30 * 32 inodes, for a news partition use more.
31 * (Scott Heavner, sdh@po.cwru.edu)
32 *
33 * 03.01.94 - Added support for file system valid flag.
34 * (Dr. Wettstein, greg%wind.uucp@plains.nodak.edu)
35 *
36 * 30.10.94 - added support for v2 filesystem
37 * (Andreas Schwab, schwab@issan.informatik.uni-dortmund.de)
38 *
39 * 09.11.94 - Added test to prevent overwrite of mounted fs adapted
40 * from Theodore Ts'o's (tytso@athena.mit.edu) mke2fs
41 * program. (Daniel Quinlan, quinlan@yggdrasil.com)
42 *
43 * 03.20.95 - Clear first 512 bytes of filesystem to make certain that
44 * the filesystem is not misidentified as a MS-DOS FAT filesystem.
45 * (Daniel Quinlan, quinlan@yggdrasil.com)
46 *
47 * 02.07.96 - Added small patch from Russell King to make the program a
48 * good deal more portable (janl@math.uio.no)
49 *
50 * Usage: mkfs [-c | -l filename ] [-v] [-nXX] [-iXX] device [size-in-blocks]
51 *
52 * -c for readability checking (SLOW!)
53 * -l for getting a list of bad blocks from a file.
54 * -n for namelength (currently the kernel only uses 14 or 30)
55 * -i for number of inodes
56 * -v for v2 filesystem
57 *
58 * The device may be a block device or a image of one, but this isn't
59 * enforced (but it's not much fun on a character device :-).
60 *
61 * Modified for BusyBox by Erik Andersen <andersen@debian.org> --
62 * removed getopt based parser and added a hand rolled one.
63 */
64
65#include "busybox.h"
66#include <mntent.h>
67
68#define DEBUG 0
69
70/* If debugging, store the very same times/uids/gids for image consistency */
71#if DEBUG
72# define CUR_TIME 0
73# define GETUID 0
74# define GETGID 0
75#else
76# define CUR_TIME time(NULL)
77# define GETUID getuid()
78# define GETGID getgid()
79#endif
80
81/*
82 * This is the original minix inode layout on disk.
83 * Note the 8-bit gid and atime and ctime.
84 */
85struct minix1_inode {
86 uint16_t i_mode;
87 uint16_t i_uid;
88 uint32_t i_size;
89 uint32_t i_time;
90 uint8_t i_gid;
91 uint8_t i_nlinks;
92 uint16_t i_zone[9];
93};
94
95/*
96 * The new minix inode has all the time entries, as well as
97 * long block numbers and a third indirect block (7+1+1+1
98 * instead of 7+1+1). Also, some previously 8-bit values are
99 * now 16-bit. The inode is now 64 bytes instead of 32.
100 */
101struct minix2_inode {
102 uint16_t i_mode;
103 uint16_t i_nlinks;
104 uint16_t i_uid;
105 uint16_t i_gid;
106 uint32_t i_size;
107 uint32_t i_atime;
108 uint32_t i_mtime;
109 uint32_t i_ctime;
110 uint32_t i_zone[10];
111};
112
113/*
114 * minix super-block data on disk
115 */
116struct minix_super_block {
117 uint16_t s_ninodes;
118 uint16_t s_nzones;
119 uint16_t s_imap_blocks;
120 uint16_t s_zmap_blocks;
121 uint16_t s_firstdatazone;
122 uint16_t s_log_zone_size;
123 uint32_t s_max_size;
124 uint16_t s_magic;
125 uint16_t s_state;
126 uint32_t s_zones;
127};
128
129struct minix_dir_entry {
130 uint16_t inode;
131 char name[0];
132};
133
134/* Believe it or not, but mount.h has this one */
135#undef BLOCK_SIZE
136enum {
137 BLOCK_SIZE = 1024,
138 BITS_PER_BLOCK = BLOCK_SIZE << 3,
139
140 MINIX_ROOT_INO = 1,
141 MINIX_BAD_INO = 2,
142 MAX_GOOD_BLOCKS = 512,
143
144 MINIX1_SUPER_MAGIC = 0x137F, /* original minix fs */
145 MINIX1_SUPER_MAGIC2 = 0x138F, /* minix fs, 30 char names */
146 MINIX2_SUPER_MAGIC = 0x2468, /* minix V2 fs */
147 MINIX2_SUPER_MAGIC2 = 0x2478, /* minix V2 fs, 30 char names */
148 MINIX_VALID_FS = 0x0001, /* clean fs */
149 MINIX_ERROR_FS = 0x0002, /* fs has errors */
150
151 INODE_SIZE1 = sizeof(struct minix1_inode),
152 INODE_SIZE2 = sizeof(struct minix2_inode),
153 MINIX1_INODES_PER_BLOCK = BLOCK_SIZE / sizeof(struct minix1_inode),
154 MINIX2_INODES_PER_BLOCK = BLOCK_SIZE / sizeof(struct minix2_inode),
155
156 TEST_BUFFER_BLOCKS = 16,
157};
158
159#if ENABLE_FEATURE_MINIX2
160static int version2;
161#else
162enum { version2 = 0 };
163#endif
164
165static char *device_name;
166static int dev_fd = -1;
167static uint32_t total_blocks;
168static int badblocks;
169/* default (changed to 30, per Linus's suggestion, Sun Nov 21 08:05:07 1993) */
170static int namelen = 30;
171static int dirsize = 32;
172static int magic = MINIX1_SUPER_MAGIC2;
173
174static char root_block[BLOCK_SIZE];
175static char super_block_buffer[BLOCK_SIZE];
176static char boot_block_buffer[512];
177static char *inode_buffer;
178
179static char *inode_map;
180static char *zone_map;
181
182static int used_good_blocks;
183static unsigned short good_blocks_table[MAX_GOOD_BLOCKS];
184static unsigned long req_nr_inodes;
185
186extern inline unsigned div_roundup(unsigned size, unsigned n)
187{
188 return (size + n-1) / n;
189}
190
191#define INODE_BUF1 (((struct minix1_inode*)inode_buffer) - 1)
192#define INODE_BUF2 (((struct minix2_inode*)inode_buffer) - 1)
193
194#define SB (*(struct minix_super_block*)super_block_buffer)
195
196#define SB_INODES (SB.s_ninodes)
197#define SB_IMAPS (SB.s_imap_blocks)
198#define SB_ZMAPS (SB.s_zmap_blocks)
199#define SB_FIRSTZONE (SB.s_firstdatazone)
200#define SB_ZONE_SIZE (SB.s_log_zone_size)
201#define SB_MAXSIZE (SB.s_max_size)
202#define SB_MAGIC (SB.s_magic)
203
204#if !ENABLE_FEATURE_MINIX2
205# define SB_ZONES (SB.s_nzones)
206# define INODE_BLOCKS div_roundup(SB_INODES, MINIX1_INODES_PER_BLOCK)
207#else
208# define SB_ZONES (version2 ? SB.s_zones : SB.s_nzones)
209# define INODE_BLOCKS div_roundup(SB_INODES, \
210 version2 ? MINIX2_INODES_PER_BLOCK : MINIX1_INODES_PER_BLOCK)
211#endif
212
213#define INODE_BUFFER_SIZE (INODE_BLOCKS * BLOCK_SIZE)
214#define NORM_FIRSTZONE (2 + SB_IMAPS + SB_ZMAPS + INODE_BLOCKS)
215
216static int bit(const char* a, unsigned i)
217{
218 return a[i >> 3] & (1<<(i & 7));
219}
220
221/* Note: do not assume 0/1, it is 0/nonzero */
222#define inode_in_use(x) bit(inode_map,(x))
223#define zone_in_use(x) bit(zone_map,(x)-SB_FIRSTZONE+1)
224
225#define mark_inode(x) setbit(inode_map,(x))
226#define unmark_inode(x) clrbit(inode_map,(x))
227#define mark_zone(x) setbit(zone_map,(x)-SB_FIRSTZONE+1)
228#define unmark_zone(x) clrbit(zone_map,(x)-SB_FIRSTZONE+1)
229
230#ifndef BLKGETSIZE
231# define BLKGETSIZE _IO(0x12,96) /* return device size */
232#endif
233
234
235static long valid_offset(int fd, int offset)
236{
237 char ch;
238
239 if (lseek(fd, offset, SEEK_SET) < 0)
240 return 0;
241 if (read(fd, &ch, 1) < 1)
242 return 0;
243 return 1;
244}
245
246static int count_blocks(int fd)
247{
248 int high, low;
249
250 low = 0;
251 for (high = 1; valid_offset(fd, high); high *= 2)
252 low = high;
253
254 while (low < high - 1) {
255 const int mid = (low + high) / 2;
256
257 if (valid_offset(fd, mid))
258 low = mid;
259 else
260 high = mid;
261 }
262 valid_offset(fd, 0);
263 return (low + 1);
264}
265
266static int get_size(const char *file)
267{
268 int fd;
269 long size;
270
271 fd = xopen(file, O_RDWR);
272 if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
273 close(fd);
274 return (size * 512);
275 }
276
277 size = count_blocks(fd);
278 close(fd);
279 return size;
280}
281
282static void write_tables(void)
283{
284 /* Mark the super block valid. */
285 SB.s_state |= MINIX_VALID_FS;
286 SB.s_state &= ~MINIX_ERROR_FS;
287
288 msg_eol = "seek to 0 failed";
289 xlseek(dev_fd, 0, SEEK_SET);
290
291 msg_eol = "cannot clear boot sector";
292 xwrite(dev_fd, boot_block_buffer, 512);
293
294 msg_eol = "seek to BLOCK_SIZE failed";
295 xlseek(dev_fd, BLOCK_SIZE, SEEK_SET);
296
297 msg_eol = "cannot write superblock";
298 xwrite(dev_fd, super_block_buffer, BLOCK_SIZE);
299
300 msg_eol = "cannot write inode map";
301 xwrite(dev_fd, inode_map, SB_IMAPS * BLOCK_SIZE);
302
303 msg_eol = "cannot write zone map";
304 xwrite(dev_fd, zone_map, SB_ZMAPS * BLOCK_SIZE);
305
306 msg_eol = "cannot write inodes";
307 xwrite(dev_fd, inode_buffer, INODE_BUFFER_SIZE);
308
309 msg_eol = "\n";
310}
311
312static void write_block(int blk, char *buffer)
313{
314 xlseek(dev_fd, blk * BLOCK_SIZE, SEEK_SET);
315 xwrite(dev_fd, buffer, BLOCK_SIZE);
316}
317
318static int get_free_block(void)
319{
320 int blk;
321
322 if (used_good_blocks + 1 >= MAX_GOOD_BLOCKS)
323 bb_error_msg_and_die("too many bad blocks");
324 if (used_good_blocks)
325 blk = good_blocks_table[used_good_blocks - 1] + 1;
326 else
327 blk = SB_FIRSTZONE;
328 while (blk < SB_ZONES && zone_in_use(blk))
329 blk++;
330 if (blk >= SB_ZONES)
331 bb_error_msg_and_die("not enough good blocks");
332 good_blocks_table[used_good_blocks] = blk;
333 used_good_blocks++;
334 return blk;
335}
336
337static void mark_good_blocks(void)
338{
339 int blk;
340
341 for (blk = 0; blk < used_good_blocks; blk++)
342 mark_zone(good_blocks_table[blk]);
343}
344
345static int next(int zone)
346{
347 if (!zone)
348 zone = SB_FIRSTZONE - 1;
349 while (++zone < SB_ZONES)
350 if (zone_in_use(zone))
351 return zone;
352 return 0;
353}
354
355static void make_bad_inode(void)
356{
357 struct minix1_inode *inode = &INODE_BUF1[MINIX_BAD_INO];
358 int i, j, zone;
359 int ind = 0, dind = 0;
360 unsigned short ind_block[BLOCK_SIZE >> 1];
361 unsigned short dind_block[BLOCK_SIZE >> 1];
362
363#define NEXT_BAD (zone = next(zone))
364
365 if (!badblocks)
366 return;
367 mark_inode(MINIX_BAD_INO);
368 inode->i_nlinks = 1;
369 /* BTW, setting this makes all images different */
370 /* it's harder to check for bugs then - diff isn't helpful :(... */
371 inode->i_time = CUR_TIME;
372 inode->i_mode = S_IFREG + 0000;
373 inode->i_size = badblocks * BLOCK_SIZE;
374 zone = next(0);
375 for (i = 0; i < 7; i++) {
376 inode->i_zone[i] = zone;
377 if (!NEXT_BAD)
378 goto end_bad;
379 }
380 inode->i_zone[7] = ind = get_free_block();
381 memset(ind_block, 0, BLOCK_SIZE);
382 for (i = 0; i < 512; i++) {
383 ind_block[i] = zone;
384 if (!NEXT_BAD)
385 goto end_bad;
386 }
387 inode->i_zone[8] = dind = get_free_block();
388 memset(dind_block, 0, BLOCK_SIZE);
389 for (i = 0; i < 512; i++) {
390 write_block(ind, (char *) ind_block);
391 dind_block[i] = ind = get_free_block();
392 memset(ind_block, 0, BLOCK_SIZE);
393 for (j = 0; j < 512; j++) {
394 ind_block[j] = zone;
395 if (!NEXT_BAD)
396 goto end_bad;
397 }
398 }
399 bb_error_msg_and_die("too many bad blocks");
400 end_bad:
401 if (ind)
402 write_block(ind, (char *) ind_block);
403 if (dind)
404 write_block(dind, (char *) dind_block);
405}
406
407#if ENABLE_FEATURE_MINIX2
408static void make_bad_inode2(void)
409{
410 struct minix2_inode *inode = &INODE_BUF2[MINIX_BAD_INO];
411 int i, j, zone;
412 int ind = 0, dind = 0;
413 unsigned long ind_block[BLOCK_SIZE >> 2];
414 unsigned long dind_block[BLOCK_SIZE >> 2];
415
416 if (!badblocks)
417 return;
418 mark_inode(MINIX_BAD_INO);
419 inode->i_nlinks = 1;
420 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
421 inode->i_mode = S_IFREG + 0000;
422 inode->i_size = badblocks * BLOCK_SIZE;
423 zone = next(0);
424 for (i = 0; i < 7; i++) {
425 inode->i_zone[i] = zone;
426 if (!NEXT_BAD)
427 goto end_bad;
428 }
429 inode->i_zone[7] = ind = get_free_block();
430 memset(ind_block, 0, BLOCK_SIZE);
431 for (i = 0; i < 256; i++) {
432 ind_block[i] = zone;
433 if (!NEXT_BAD)
434 goto end_bad;
435 }
436 inode->i_zone[8] = dind = get_free_block();
437 memset(dind_block, 0, BLOCK_SIZE);
438 for (i = 0; i < 256; i++) {
439 write_block(ind, (char *) ind_block);
440 dind_block[i] = ind = get_free_block();
441 memset(ind_block, 0, BLOCK_SIZE);
442 for (j = 0; j < 256; j++) {
443 ind_block[j] = zone;
444 if (!NEXT_BAD)
445 goto end_bad;
446 }
447 }
448 /* Could make triple indirect block here */
449 bb_error_msg_and_die("too many bad blocks");
450 end_bad:
451 if (ind)
452 write_block(ind, (char *) ind_block);
453 if (dind)
454 write_block(dind, (char *) dind_block);
455}
456#endif
457
458static void make_root_inode(void)
459{
460 struct minix1_inode *inode = &INODE_BUF1[MINIX_ROOT_INO];
461
462 mark_inode(MINIX_ROOT_INO);
463 inode->i_zone[0] = get_free_block();
464 inode->i_nlinks = 2;
465 inode->i_time = CUR_TIME;
466 if (badblocks)
467 inode->i_size = 3 * dirsize;
468 else {
469 root_block[2 * dirsize] = '\0';
470 root_block[2 * dirsize + 1] = '\0';
471 inode->i_size = 2 * dirsize;
472 }
473 inode->i_mode = S_IFDIR + 0755;
474 inode->i_uid = GETUID;
475 if (inode->i_uid)
476 inode->i_gid = GETGID;
477 write_block(inode->i_zone[0], root_block);
478}
479
480#if ENABLE_FEATURE_MINIX2
481static void make_root_inode2(void)
482{
483 struct minix2_inode *inode = &INODE_BUF2[MINIX_ROOT_INO];
484
485 mark_inode(MINIX_ROOT_INO);
486 inode->i_zone[0] = get_free_block();
487 inode->i_nlinks = 2;
488 inode->i_atime = inode->i_mtime = inode->i_ctime = CUR_TIME;
489 if (badblocks)
490 inode->i_size = 3 * dirsize;
491 else {
492 root_block[2 * dirsize] = '\0';
493 root_block[2 * dirsize + 1] = '\0';
494 inode->i_size = 2 * dirsize;
495 }
496 inode->i_mode = S_IFDIR + 0755;
497 inode->i_uid = GETUID;
498 if (inode->i_uid)
499 inode->i_gid = GETGID;
500 write_block(inode->i_zone[0], root_block);
501}
502#endif
503
504static void setup_tables(void)
505{
506 unsigned long inodes;
507 unsigned norm_firstzone;
508 unsigned sb_zmaps;
509 unsigned i;
510
511 memset(super_block_buffer, 0, BLOCK_SIZE);
512 memset(boot_block_buffer, 0, 512);
513 SB_MAGIC = magic;
514 SB_ZONE_SIZE = 0;
515 SB_MAXSIZE = version2 ? 0x7fffffff : (7 + 512 + 512 * 512) * 1024;
516 if (version2)
517 SB.s_zones = total_blocks;
518 else
519 SB.s_nzones = total_blocks;
520
521 /* some magic nrs: 1 inode / 3 blocks */
522 if (req_nr_inodes == 0)
523 inodes = total_blocks / 3;
524 else
525 inodes = req_nr_inodes;
526 /* Round up inode count to fill block size */
527 if (version2)
528 inodes = (inodes + MINIX2_INODES_PER_BLOCK - 1) &
529 ~(MINIX2_INODES_PER_BLOCK - 1);
530 else
531 inodes = (inodes + MINIX1_INODES_PER_BLOCK - 1) &
532 ~(MINIX1_INODES_PER_BLOCK - 1);
533 if (inodes > 65535)
534 inodes = 65535;
535 SB_INODES = inodes;
536 SB_IMAPS = div_roundup(SB_INODES + 1, BITS_PER_BLOCK);
537
538 /* Real bad hack but overwise mkfs.minix can be thrown
539 * in infinite loop...
540 * try:
541 * dd if=/dev/zero of=test.fs count=10 bs=1024
542 * mkfs.minix -i 200 test.fs
543 */
544 /* This code is not insane: NORM_FIRSTZONE is not a constant,
545 * it is calculated from SB_INODES, SB_IMAPS and SB_ZMAPS */
546 i = 999;
547 SB_ZMAPS = 0;
548 do {
549 norm_firstzone = NORM_FIRSTZONE;
550 sb_zmaps = div_roundup(total_blocks - norm_firstzone + 1, BITS_PER_BLOCK);
551 if (SB_ZMAPS == sb_zmaps) goto got_it;
552 SB_ZMAPS = sb_zmaps;
553 /* new SB_ZMAPS, need to recalc NORM_FIRSTZONE */
554 } while (--i);
555 bb_error_msg_and_die("incompatible size/inode count, try different -i N");
556 got_it:
557
558 SB_FIRSTZONE = norm_firstzone;
559 inode_map = xmalloc(SB_IMAPS * BLOCK_SIZE);
560 zone_map = xmalloc(SB_ZMAPS * BLOCK_SIZE);
561 memset(inode_map, 0xff, SB_IMAPS * BLOCK_SIZE);
562 memset(zone_map, 0xff, SB_ZMAPS * BLOCK_SIZE);
563 for (i = SB_FIRSTZONE; i < SB_ZONES; i++)
564 unmark_zone(i);
565 for (i = MINIX_ROOT_INO; i <= SB_INODES; i++)
566 unmark_inode(i);
567 inode_buffer = xzalloc(INODE_BUFFER_SIZE);
568 printf("%ld inodes\n", (long)SB_INODES);
569 printf("%ld blocks\n", (long)SB_ZONES);
570 printf("Firstdatazone=%ld (%ld)\n", (long)SB_FIRSTZONE, (long)norm_firstzone);
571 printf("Zonesize=%d\n", BLOCK_SIZE << SB_ZONE_SIZE);
572 printf("Maxsize=%ld\n", (long)SB_MAXSIZE);
573}
574
575/*
576 * Perform a test of a block; return the number of
577 * blocks readable/writable.
578 */
579static long do_check(char *buffer, int try, unsigned current_block)
580{
581 long got;
582
583 /* Seek to the correct loc. */
584 msg_eol = "seek failed during testing of blocks";
585 xlseek(dev_fd, current_block * BLOCK_SIZE, SEEK_SET);
586 msg_eol = "\n";
587
588 /* Try the read */
589 got = read(dev_fd, buffer, try * BLOCK_SIZE);
590 if (got < 0)
591 got = 0;
592 if (got & (BLOCK_SIZE - 1)) {
593 printf("Weird values in do_check: probably bugs\n");
594 }
595 got /= BLOCK_SIZE;
596 return got;
597}
598
599static unsigned currently_testing;
600
601static void alarm_intr(int alnum)
602{
603 if (currently_testing >= SB_ZONES)
604 return;
605 signal(SIGALRM, alarm_intr);
606 alarm(5);
607 if (!currently_testing)
608 return;
609 printf("%d ...", currently_testing);
610 fflush(stdout);
611}
612
613static void check_blocks(void)
614{
615 int try, got;
616 /* buffer[] was the biggest static in entire bbox */
617 char *buffer = xmalloc(BLOCK_SIZE * TEST_BUFFER_BLOCKS);
618
619 currently_testing = 0;
620 signal(SIGALRM, alarm_intr);
621 alarm(5);
622 while (currently_testing < SB_ZONES) {
623 msg_eol = "seek failed in check_blocks";
624 xlseek(dev_fd, currently_testing * BLOCK_SIZE, SEEK_SET);
625 msg_eol = "\n";
626 try = TEST_BUFFER_BLOCKS;
627 if (currently_testing + try > SB_ZONES)
628 try = SB_ZONES - currently_testing;
629 got = do_check(buffer, try, currently_testing);
630 currently_testing += got;
631 if (got == try)
632 continue;
633 if (currently_testing < SB_FIRSTZONE)
634 bb_error_msg_and_die("bad blocks before data-area: cannot make fs");
635 mark_zone(currently_testing);
636 badblocks++;
637 currently_testing++;
638 }
639 free(buffer);
640 printf("%d bad block(s)\n", badblocks);
641}
642
643static void get_list_blocks(char *filename)
644{
645 FILE *listfile;
646 unsigned long blockno;
647
648 listfile = xfopen(filename, "r");
649 while (!feof(listfile)) {
650 fscanf(listfile, "%ld\n", &blockno);
651 mark_zone(blockno);
652 badblocks++;
653 }
654 printf("%d bad block(s)\n", badblocks);
655}
656
657int mkfs_minix_main(int argc, char **argv)
658{
659 struct mntent *mp;
660 unsigned opt;
661 char *tmp;
662 struct stat statbuf;
663 char *str_i, *str_n;
664 char *listfile = NULL;
665
666 if (INODE_SIZE1 * MINIX1_INODES_PER_BLOCK != BLOCK_SIZE)
667 bb_error_msg_and_die("bad inode size");
668#if ENABLE_FEATURE_MINIX2
669 if (INODE_SIZE2 * MINIX2_INODES_PER_BLOCK != BLOCK_SIZE)
670 bb_error_msg_and_die("bad inode size");
671#endif
672
673 opt = getopt32(argc, argv, "ci:l:n:v", &str_i, &listfile, &str_n);
674 argv += optind;
675 //if (opt & 1) -c
676 if (opt & 2) req_nr_inodes = xatoul(str_i); // -i
677 //if (opt & 4) -l
678 if (opt & 8) { // -n
679 namelen = xatoi_u(str_n);
680 if (namelen == 14) magic = MINIX1_SUPER_MAGIC;
681 else if (namelen == 30) magic = MINIX1_SUPER_MAGIC2;
682 else bb_show_usage();
683 dirsize = namelen + 2;
684 }
685 if (opt & 0x10) { // -v
686#if ENABLE_FEATURE_MINIX2
687 version2 = 1;
688#else
689 bb_error_msg_and_die("%s: not compiled with minix v2 support",
690 device_name);
691#endif
692 }
693
694 device_name = *argv++;
695 if (!device_name)
696 bb_show_usage();
697 if (*argv)
698 total_blocks = xatou32(*argv);
699 else
700 total_blocks = get_size(device_name) / 1024;
701
702 if (total_blocks < 10)
703 bb_error_msg_and_die("must have at least 10 blocks");
704
705 if (version2) {
706 magic = MINIX2_SUPER_MAGIC2;
707 if (namelen == 14)
708 magic = MINIX2_SUPER_MAGIC;
709 } else if (total_blocks > 65535)
710 total_blocks = 65535;
711
712 /* Check if it is mounted */
713 mp = find_mount_point(device_name, NULL);
714 if (mp && strcmp(device_name, mp->mnt_fsname) == 0)
715 bb_error_msg_and_die("%s is mounted on %s; "
716 "refusing to make a filesystem",
717 device_name, mp->mnt_dir);
718
719 dev_fd = xopen(device_name, O_RDWR);
720 if (fstat(dev_fd, &statbuf) < 0)
721 bb_error_msg_and_die("cannot stat %s", device_name);
722 if (!S_ISBLK(statbuf.st_mode))
723 opt &= ~1; // clear -c (check)
724
725/* I don't know why someone has special code to prevent mkfs.minix
726 * on IDE devices. Why IDE but not SCSI, etc?... */
727#if 0
728 else if (statbuf.st_rdev == 0x0300 || statbuf.st_rdev == 0x0340)
729 /* what is this? */
730 bb_error_msg_and_die("will not try "
731 "to make filesystem on '%s'", device_name);
732#endif
733
734 tmp = root_block;
735 *(short *) tmp = 1;
736 strcpy(tmp + 2, ".");
737 tmp += dirsize;
738 *(short *) tmp = 1;
739 strcpy(tmp + 2, "..");
740 tmp += dirsize;
741 *(short *) tmp = 2;
742 strcpy(tmp + 2, ".badblocks");
743
744 setup_tables();
745
746 if (opt & 1) // -c ?
747 check_blocks();
748 else if (listfile)
749 get_list_blocks(listfile);
750
751 if (version2) {
752 make_root_inode2();
753 make_bad_inode2();
754 } else {
755 make_root_inode();
756 make_bad_inode();
757 }
758
759 mark_good_blocks();
760 write_tables();
761 return 0;
762}
diff --git a/util-linux/mkswap.c b/util-linux/mkswap.c
new file mode 100644
index 000000000..7baa3ecfb
--- /dev/null
+++ b/util-linux/mkswap.c
@@ -0,0 +1,47 @@
1/* vi: set sw=4 ts=4: */
2/* mkswap.c - format swap device (Linux v1 only)
3 *
4 * Copyright 2006 Rob Landley <rob@landley.net>
5 *
6 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
7 */
8
9#include "busybox.h"
10
11int mkswap_main(int argc, char *argv[])
12{
13 int fd, pagesize;
14 off_t len;
15 unsigned int hdr[129];
16
17 // No options supported.
18
19 if (argc != 2) bb_show_usage();
20
21 // Figure out how big the device is and announce our intentions.
22
23 fd = xopen(argv[1], O_RDWR);
24 len = fdlength(fd);
25 pagesize = getpagesize();
26 printf("Setting up swapspace version 1, size = %"OFF_FMT"d bytes\n",
27 len - pagesize);
28
29 // Make a header.
30
31 memset(hdr, 0, sizeof(hdr));
32 hdr[0] = 1;
33 hdr[1] = (len / pagesize) - 1;
34
35 // Write the header. Sync to disk because some kernel versions check
36 // signature on disk (not in cache) during swapon.
37
38 xlseek(fd, 1024, SEEK_SET);
39 xwrite(fd, hdr, sizeof(hdr));
40 xlseek(fd, pagesize-10, SEEK_SET);
41 xwrite(fd, "SWAPSPACE2", 10);
42 fsync(fd);
43
44 if (ENABLE_FEATURE_CLEAN_UP) close(fd);
45
46 return 0;
47}
diff --git a/util-linux/more.c b/util-linux/more.c
new file mode 100644
index 000000000..d048ace92
--- /dev/null
+++ b/util-linux/more.c
@@ -0,0 +1,177 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini more implementation for busybox
4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 *
8 * Latest version blended together by Erik Andersen <andersen@codepoet.org>,
9 * based on the original more implementation by Bruce, and code from the
10 * Debian boot-floppies team.
11 *
12 * Termios corrects by Vladimir Oleynik <dzo@simtreas.ru>
13 *
14 * Licensed under GPLv2 or later, see file License in this tarball for details.
15 */
16
17#include "busybox.h"
18
19
20#if ENABLE_FEATURE_USE_TERMIOS
21static int cin_fileno;
22#include <termios.h>
23#define setTermSettings(fd, argp) tcsetattr(fd, TCSANOW, argp)
24#define getTermSettings(fd, argp) tcgetattr(fd, argp);
25
26static struct termios initial_settings, new_settings;
27
28static void set_tty_to_initial_mode(void)
29{
30 setTermSettings(cin_fileno, &initial_settings);
31}
32
33static void gotsig(int sig)
34{
35 putchar('\n');
36 exit(EXIT_FAILURE);
37}
38#endif /* FEATURE_USE_TERMIOS */
39
40
41int more_main(int argc, char **argv)
42{
43 int c, lines, input = 0;
44 int please_display_more_prompt = 0;
45 struct stat st;
46 FILE *file;
47 FILE *cin;
48 int len, page_height;
49 int terminal_width;
50 int terminal_height;
51
52 argc--;
53 argv++;
54
55 cin = stdin;
56 /* use input from terminal unless we do "more >outfile" */
57 if (isatty(STDOUT_FILENO)) {
58 cin = fopen(CURRENT_TTY, "r");
59 if (!cin)
60 cin = xfopen(CONSOLE_DEV, "r");
61 please_display_more_prompt = 2;
62#if ENABLE_FEATURE_USE_TERMIOS
63 cin_fileno = fileno(cin);
64 getTermSettings(cin_fileno, &initial_settings);
65 new_settings = initial_settings;
66 new_settings.c_lflag &= ~ICANON;
67 new_settings.c_lflag &= ~ECHO;
68 new_settings.c_cc[VMIN] = 1;
69 new_settings.c_cc[VTIME] = 0;
70 setTermSettings(cin_fileno, &new_settings);
71 atexit(set_tty_to_initial_mode);
72 signal(SIGINT, gotsig);
73 signal(SIGQUIT, gotsig);
74 signal(SIGTERM, gotsig);
75#endif
76 }
77
78 do {
79 file = stdin;
80 if (argc != 0) {
81 file = fopen_or_warn(*argv, "r");
82 if (!file)
83 goto loop;
84 }
85
86 st.st_size = 0;
87 fstat(fileno(file), &st);
88
89 please_display_more_prompt &= ~1;
90
91 get_terminal_width_height(fileno(cin), &terminal_width, &terminal_height);
92 if (terminal_height > 4)
93 terminal_height -= 2;
94 if (terminal_width > 0)
95 terminal_width -= 1;
96
97 len = 0;
98 lines = 0;
99 page_height = terminal_height;
100 while ((c = getc(file)) != EOF) {
101
102 if ((please_display_more_prompt & 3) == 3) {
103 len = printf("--More-- ");
104 if (file != stdin && st.st_size > 0) {
105 len += printf("(%d%% of %"OFF_FMT"d bytes)",
106 (int) (ftello(file)*100 / st.st_size),
107 st.st_size);
108 }
109 fflush(stdout);
110
111 /*
112 * We've just displayed the "--More--" prompt, so now we need
113 * to get input from the user.
114 */
115 input = getc(cin);
116#if !ENABLE_FEATURE_USE_TERMIOS
117 printf("\033[A"); /* up cursor */
118#endif
119 /* Erase the "More" message */
120 printf("\r%*s\r", len, "");
121 len = 0;
122 lines = 0;
123 page_height = terminal_height;
124 please_display_more_prompt &= ~1;
125
126 if (input == 'q')
127 goto end;
128 }
129
130 /*
131 * There are two input streams to worry about here:
132 *
133 * c : the character we are reading from the file being "mored"
134 * input : a character received from the keyboard
135 *
136 * If we hit a newline in the _file_ stream, we want to test and
137 * see if any characters have been hit in the _input_ stream. This
138 * allows the user to quit while in the middle of a file.
139 */
140 if (c == '\n') {
141 /* increment by just one line if we are at
142 * the end of this line */
143 if (input == '\n')
144 please_display_more_prompt |= 1;
145 /* Adjust the terminal height for any overlap, so that
146 * no lines get lost off the top. */
147 if (len >= terminal_width) {
148 int quot, rem;
149 quot = len / terminal_width;
150 rem = len - (quot * terminal_width);
151 if (quot) {
152 if (rem)
153 page_height -= quot;
154 else
155 page_height -= (quot - 1);
156 }
157 }
158 if (++lines >= page_height) {
159 please_display_more_prompt |= 1;
160 }
161 len = 0;
162 }
163 /*
164 * If we just read a newline from the file being 'mored' and any
165 * key other than a return is hit, scroll by one page
166 */
167 putc(c, stdout);
168 len++;
169 }
170 fclose(file);
171 fflush(stdout);
172 loop:
173 argv++;
174 } while (--argc > 0);
175 end:
176 return 0;
177}
diff --git a/util-linux/mount.c b/util-linux/mount.c
new file mode 100644
index 000000000..f8ae1df19
--- /dev/null
+++ b/util-linux/mount.c
@@ -0,0 +1,1712 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini mount implementation for busybox
4 *
5 * Copyright (C) 1995, 1996 by Bruce Perens <bruce@pixar.com>.
6 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
7 * Copyright (C) 2005-2006 by Rob Landley <rob@landley.net>
8 *
9 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
10 */
11
12/* Design notes: There is no spec for mount. Remind me to write one.
13
14 mount_main() calls singlemount() which calls mount_it_now().
15
16 mount_main() can loop through /etc/fstab for mount -a
17 singlemount() can loop through /etc/filesystems for fstype detection.
18 mount_it_now() does the actual mount.
19*/
20
21#include "busybox.h"
22#include <mntent.h>
23
24/* Needed for nfs support only... */
25#include <syslog.h>
26#include <sys/utsname.h>
27#undef TRUE
28#undef FALSE
29#include <rpc/rpc.h>
30#include <rpc/pmap_prot.h>
31#include <rpc/pmap_clnt.h>
32
33
34// Not real flags, but we want to be able to check for this.
35enum {
36 MOUNT_USERS = (1<<28)*ENABLE_DESKTOP,
37 MOUNT_NOAUTO = (1<<29),
38 MOUNT_SWAP = (1<<30),
39};
40// TODO: more "user" flag compatibility.
41// "user" option (from mount manpage):
42// Only the user that mounted a filesystem can unmount it again.
43// If any user should be able to unmount, then use users instead of user
44// in the fstab line. The owner option is similar to the user option,
45// with the restriction that the user must be the owner of the special file.
46// This may be useful e.g. for /dev/fd if a login script makes
47// the console user owner of this device.
48
49/* Standard mount options (from -o options or --options), with corresponding
50 * flags */
51
52struct {
53 char *name;
54 long flags;
55} static mount_options[] = {
56 // MS_FLAGS set a bit. ~MS_FLAGS disable that bit. 0 flags are NOPs.
57
58 USE_FEATURE_MOUNT_LOOP(
59 {"loop", 0},
60 )
61
62 USE_FEATURE_MOUNT_FSTAB(
63 {"defaults", 0},
64 /* {"quiet", 0}, - do not filter out, vfat wants to see it */
65 {"noauto", MOUNT_NOAUTO},
66 {"swap", MOUNT_SWAP},
67 USE_DESKTOP({"user", MOUNT_USERS},)
68 USE_DESKTOP({"users", MOUNT_USERS},)
69 )
70
71 USE_FEATURE_MOUNT_FLAGS(
72 // vfs flags
73 {"nosuid", MS_NOSUID},
74 {"suid", ~MS_NOSUID},
75 {"dev", ~MS_NODEV},
76 {"nodev", MS_NODEV},
77 {"exec", ~MS_NOEXEC},
78 {"noexec", MS_NOEXEC},
79 {"sync", MS_SYNCHRONOUS},
80 {"async", ~MS_SYNCHRONOUS},
81 {"atime", ~MS_NOATIME},
82 {"noatime", MS_NOATIME},
83 {"diratime", ~MS_NODIRATIME},
84 {"nodiratime", MS_NODIRATIME},
85 {"loud", ~MS_SILENT},
86
87 // action flags
88
89 {"bind", MS_BIND},
90 {"move", MS_MOVE},
91 {"shared", MS_SHARED},
92 {"slave", MS_SLAVE},
93 {"private", MS_PRIVATE},
94 {"unbindable", MS_UNBINDABLE},
95 {"rshared", MS_SHARED|MS_RECURSIVE},
96 {"rslave", MS_SLAVE|MS_RECURSIVE},
97 {"rprivate", MS_SLAVE|MS_RECURSIVE},
98 {"runbindable", MS_UNBINDABLE|MS_RECURSIVE},
99 )
100
101 // Always understood.
102
103 {"ro", MS_RDONLY}, // vfs flag
104 {"rw", ~MS_RDONLY}, // vfs flag
105 {"remount", MS_REMOUNT}, // action flag
106};
107
108#define VECTOR_SIZE(v) (sizeof(v) / sizeof((v)[0]))
109
110/* Append mount options to string */
111static void append_mount_options(char **oldopts, char *newopts)
112{
113 if (*oldopts && **oldopts) {
114 /* do not insert options which are already there */
115 while (newopts[0]) {
116 char *p;
117 int len = strlen(newopts);
118 p = strchr(newopts, ',');
119 if (p) len = p - newopts;
120 p = *oldopts;
121 while (1) {
122 if (!strncmp(p, newopts, len)
123 && (p[len]==',' || p[len]==0))
124 goto skip;
125 p = strchr(p,',');
126 if(!p) break;
127 p++;
128 }
129 p = xasprintf("%s,%.*s", *oldopts, len, newopts);
130 free(*oldopts);
131 *oldopts = p;
132skip:
133 newopts += len;
134 while (newopts[0] == ',') newopts++;
135 }
136 } else {
137 if (ENABLE_FEATURE_CLEAN_UP) free(*oldopts);
138 *oldopts = xstrdup(newopts);
139 }
140}
141
142/* Use the mount_options list to parse options into flags.
143 * Also return list of unrecognized options if unrecognized!=NULL */
144static int parse_mount_options(char *options, char **unrecognized)
145{
146 int flags = MS_SILENT;
147
148 // Loop through options
149 for (;;) {
150 int i;
151 char *comma = strchr(options, ',');
152
153 if (comma) *comma = 0;
154
155 // Find this option in mount_options
156 for (i = 0; i < VECTOR_SIZE(mount_options); i++) {
157 if (!strcasecmp(mount_options[i].name, options)) {
158 long fl = mount_options[i].flags;
159 if (fl < 0) flags &= fl;
160 else flags |= fl;
161 break;
162 }
163 }
164 // If unrecognized not NULL, append unrecognized mount options */
165 if (unrecognized && i == VECTOR_SIZE(mount_options)) {
166 // Add it to strflags, to pass on to kernel
167 i = *unrecognized ? strlen(*unrecognized) : 0;
168 *unrecognized = xrealloc(*unrecognized, i+strlen(options)+2);
169
170 // Comma separated if it's not the first one
171 if (i) (*unrecognized)[i++] = ',';
172 strcpy((*unrecognized)+i, options);
173 }
174
175 // Advance to next option, or finish
176 if (comma) {
177 *comma = ',';
178 options = ++comma;
179 } else break;
180 }
181
182 return flags;
183}
184
185// Return a list of all block device backed filesystems
186
187static llist_t *get_block_backed_filesystems(void)
188{
189 static const char *const filesystems[] = {
190 "/etc/filesystems",
191 "/proc/filesystems",
192 0
193 };
194 char *fs, *buf;
195 llist_t *list = 0;
196 int i;
197 FILE *f;
198
199 for (i = 0; filesystems[i]; i++) {
200 f = fopen(filesystems[i], "r");
201 if (!f) continue;
202
203 while ((buf = xmalloc_getline(f)) != 0) {
204 if (!strncmp(buf, "nodev", 5) && isspace(buf[5]))
205 continue;
206 fs = skip_whitespace(buf);
207 if (*fs=='#' || *fs=='*' || !*fs) continue;
208
209 llist_add_to_end(&list, xstrdup(fs));
210 free(buf);
211 }
212 if (ENABLE_FEATURE_CLEAN_UP) fclose(f);
213 }
214
215 return list;
216}
217
218llist_t *fslist = 0;
219
220#if ENABLE_FEATURE_CLEAN_UP
221static void delete_block_backed_filesystems(void)
222{
223 llist_free(fslist, free);
224}
225#else
226void delete_block_backed_filesystems(void);
227#endif
228
229#if ENABLE_FEATURE_MTAB_SUPPORT
230static int useMtab = 1;
231static int fakeIt;
232#else
233#define useMtab 0
234#define fakeIt 0
235#endif
236
237// Perform actual mount of specific filesystem at specific location.
238// NB: mp->xxx fields may be trashed on exit
239static int mount_it_now(struct mntent *mp, int vfsflags, char *filteropts)
240{
241 int rc = 0;
242
243 if (fakeIt) goto mtab;
244
245 // Mount, with fallback to read-only if necessary.
246
247 for (;;) {
248 rc = mount(mp->mnt_fsname, mp->mnt_dir, mp->mnt_type,
249 vfsflags, filteropts);
250 if (!rc || (vfsflags&MS_RDONLY) || (errno!=EACCES && errno!=EROFS))
251 break;
252 bb_error_msg("%s is write-protected, mounting read-only",
253 mp->mnt_fsname);
254 vfsflags |= MS_RDONLY;
255 }
256
257 // Abort entirely if permission denied.
258
259 if (rc && errno == EPERM)
260 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
261
262 /* If the mount was successful, and we're maintaining an old-style
263 * mtab file by hand, add the new entry to it now. */
264 mtab:
265 if (ENABLE_FEATURE_MTAB_SUPPORT && useMtab && !rc && !(vfsflags & MS_REMOUNT)) {
266 char *fsname;
267 FILE *mountTable = setmntent(bb_path_mtab_file, "a+");
268 int i;
269
270 if (!mountTable) {
271 bb_error_msg("no %s",bb_path_mtab_file);
272 goto ret;
273 }
274
275 // Add vfs string flags
276
277 for (i=0; mount_options[i].flags != MS_REMOUNT; i++)
278 if (mount_options[i].flags > 0 && (mount_options[i].flags & vfsflags))
279 append_mount_options(&(mp->mnt_opts), mount_options[i].name);
280
281 // Remove trailing / (if any) from directory we mounted on
282
283 i = strlen(mp->mnt_dir) - 1;
284 if (i > 0 && mp->mnt_dir[i] == '/') mp->mnt_dir[i] = 0;
285
286 // Convert to canonical pathnames as needed
287
288 mp->mnt_dir = bb_simplify_path(mp->mnt_dir);
289 fsname = 0;
290 if (!mp->mnt_type || !*mp->mnt_type) { /* bind mount */
291 mp->mnt_fsname = fsname = bb_simplify_path(mp->mnt_fsname);
292 mp->mnt_type = "bind";
293 }
294 mp->mnt_freq = mp->mnt_passno = 0;
295
296 // Write and close.
297
298 addmntent(mountTable, mp);
299 endmntent(mountTable);
300 if (ENABLE_FEATURE_CLEAN_UP) {
301 free(mp->mnt_dir);
302 free(fsname);
303 }
304 }
305 ret:
306 return rc;
307}
308
309#if ENABLE_FEATURE_MOUNT_NFS
310
311/*
312 * Linux NFS mount
313 * Copyright (C) 1993 Rick Sladkey <jrs@world.std.com>
314 *
315 * Licensed under GPLv2, see file LICENSE in this tarball for details.
316 *
317 * Wed Feb 8 12:51:48 1995, biro@yggdrasil.com (Ross Biro): allow all port
318 * numbers to be specified on the command line.
319 *
320 * Fri, 8 Mar 1996 18:01:39, Swen Thuemmler <swen@uni-paderborn.de>:
321 * Omit the call to connect() for Linux version 1.3.11 or later.
322 *
323 * Wed Oct 1 23:55:28 1997: Dick Streefland <dick_streefland@tasking.com>
324 * Implemented the "bg", "fg" and "retry" mount options for NFS.
325 *
326 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@misiek.eu.org>
327 * - added Native Language Support
328 *
329 * Modified by Olaf Kirch and Trond Myklebust for new NFS code,
330 * plus NFSv3 stuff.
331 */
332
333/* This is just a warning of a common mistake. Possibly this should be a
334 * uclibc faq entry rather than in busybox... */
335#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
336#error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support."
337#endif
338
339#define MOUNTPORT 635
340#define MNTPATHLEN 1024
341#define MNTNAMLEN 255
342#define FHSIZE 32
343#define FHSIZE3 64
344
345typedef char fhandle[FHSIZE];
346
347typedef struct {
348 unsigned int fhandle3_len;
349 char *fhandle3_val;
350} fhandle3;
351
352enum mountstat3 {
353 MNT_OK = 0,
354 MNT3ERR_PERM = 1,
355 MNT3ERR_NOENT = 2,
356 MNT3ERR_IO = 5,
357 MNT3ERR_ACCES = 13,
358 MNT3ERR_NOTDIR = 20,
359 MNT3ERR_INVAL = 22,
360 MNT3ERR_NAMETOOLONG = 63,
361 MNT3ERR_NOTSUPP = 10004,
362 MNT3ERR_SERVERFAULT = 10006,
363};
364typedef enum mountstat3 mountstat3;
365
366struct fhstatus {
367 unsigned int fhs_status;
368 union {
369 fhandle fhs_fhandle;
370 } fhstatus_u;
371};
372typedef struct fhstatus fhstatus;
373
374struct mountres3_ok {
375 fhandle3 fhandle;
376 struct {
377 unsigned int auth_flavours_len;
378 char *auth_flavours_val;
379 } auth_flavours;
380};
381typedef struct mountres3_ok mountres3_ok;
382
383struct mountres3 {
384 mountstat3 fhs_status;
385 union {
386 mountres3_ok mountinfo;
387 } mountres3_u;
388};
389typedef struct mountres3 mountres3;
390
391typedef char *dirpath;
392
393typedef char *name;
394
395typedef struct mountbody *mountlist;
396
397struct mountbody {
398 name ml_hostname;
399 dirpath ml_directory;
400 mountlist ml_next;
401};
402typedef struct mountbody mountbody;
403
404typedef struct groupnode *groups;
405
406struct groupnode {
407 name gr_name;
408 groups gr_next;
409};
410typedef struct groupnode groupnode;
411
412typedef struct exportnode *exports;
413
414struct exportnode {
415 dirpath ex_dir;
416 groups ex_groups;
417 exports ex_next;
418};
419typedef struct exportnode exportnode;
420
421struct ppathcnf {
422 int pc_link_max;
423 short pc_max_canon;
424 short pc_max_input;
425 short pc_name_max;
426 short pc_path_max;
427 short pc_pipe_buf;
428 u_char pc_vdisable;
429 char pc_xxx;
430 short pc_mask[2];
431};
432typedef struct ppathcnf ppathcnf;
433
434#define MOUNTPROG 100005
435#define MOUNTVERS 1
436
437#define MOUNTPROC_NULL 0
438#define MOUNTPROC_MNT 1
439#define MOUNTPROC_DUMP 2
440#define MOUNTPROC_UMNT 3
441#define MOUNTPROC_UMNTALL 4
442#define MOUNTPROC_EXPORT 5
443#define MOUNTPROC_EXPORTALL 6
444
445#define MOUNTVERS_POSIX 2
446
447#define MOUNTPROC_PATHCONF 7
448
449#define MOUNT_V3 3
450
451#define MOUNTPROC3_NULL 0
452#define MOUNTPROC3_MNT 1
453#define MOUNTPROC3_DUMP 2
454#define MOUNTPROC3_UMNT 3
455#define MOUNTPROC3_UMNTALL 4
456#define MOUNTPROC3_EXPORT 5
457
458enum {
459#ifndef NFS_FHSIZE
460 NFS_FHSIZE = 32,
461#endif
462#ifndef NFS_PORT
463 NFS_PORT = 2049
464#endif
465};
466
467/*
468 * We want to be able to compile mount on old kernels in such a way
469 * that the binary will work well on more recent kernels.
470 * Thus, if necessary we teach nfsmount.c the structure of new fields
471 * that will come later.
472 *
473 * Moreover, the new kernel includes conflict with glibc includes
474 * so it is easiest to ignore the kernel altogether (at compile time).
475 */
476
477struct nfs2_fh {
478 char data[32];
479};
480struct nfs3_fh {
481 unsigned short size;
482 unsigned char data[64];
483};
484
485struct nfs_mount_data {
486 int version; /* 1 */
487 int fd; /* 1 */
488 struct nfs2_fh old_root; /* 1 */
489 int flags; /* 1 */
490 int rsize; /* 1 */
491 int wsize; /* 1 */
492 int timeo; /* 1 */
493 int retrans; /* 1 */
494 int acregmin; /* 1 */
495 int acregmax; /* 1 */
496 int acdirmin; /* 1 */
497 int acdirmax; /* 1 */
498 struct sockaddr_in addr; /* 1 */
499 char hostname[256]; /* 1 */
500 int namlen; /* 2 */
501 unsigned int bsize; /* 3 */
502 struct nfs3_fh root; /* 4 */
503};
504
505/* bits in the flags field */
506enum {
507 NFS_MOUNT_SOFT = 0x0001, /* 1 */
508 NFS_MOUNT_INTR = 0x0002, /* 1 */
509 NFS_MOUNT_SECURE = 0x0004, /* 1 */
510 NFS_MOUNT_POSIX = 0x0008, /* 1 */
511 NFS_MOUNT_NOCTO = 0x0010, /* 1 */
512 NFS_MOUNT_NOAC = 0x0020, /* 1 */
513 NFS_MOUNT_TCP = 0x0040, /* 2 */
514 NFS_MOUNT_VER3 = 0x0080, /* 3 */
515 NFS_MOUNT_KERBEROS = 0x0100, /* 3 */
516 NFS_MOUNT_NONLM = 0x0200 /* 3 */
517};
518
519
520/*
521 * We need to translate between nfs status return values and
522 * the local errno values which may not be the same.
523 *
524 * Andreas Schwab <schwab@LS5.informatik.uni-dortmund.de>: change errno:
525 * "after #include <errno.h> the symbol errno is reserved for any use,
526 * it cannot even be used as a struct tag or field name".
527 */
528
529#ifndef EDQUOT
530#define EDQUOT ENOSPC
531#endif
532
533// Convert each NFSERR_BLAH into EBLAH
534
535static const struct {
536 int stat;
537 int errnum;
538} nfs_errtbl[] = {
539 {0,0}, {1,EPERM}, {2,ENOENT}, {5,EIO}, {6,ENXIO}, {13,EACCES}, {17,EEXIST},
540 {19,ENODEV}, {20,ENOTDIR}, {21,EISDIR}, {22,EINVAL}, {27,EFBIG},
541 {28,ENOSPC}, {30,EROFS}, {63,ENAMETOOLONG}, {66,ENOTEMPTY}, {69,EDQUOT},
542 {70,ESTALE}, {71,EREMOTE}, {-1,EIO}
543};
544
545static char *nfs_strerror(int status)
546{
547 int i;
548 static char buf[sizeof("unknown nfs status return value: ") + sizeof(int)*3];
549
550 for (i = 0; nfs_errtbl[i].stat != -1; i++) {
551 if (nfs_errtbl[i].stat == status)
552 return strerror(nfs_errtbl[i].errnum);
553 }
554 sprintf(buf, "unknown nfs status return value: %d", status);
555 return buf;
556}
557
558static bool_t xdr_fhandle(XDR *xdrs, fhandle objp)
559{
560 if (!xdr_opaque(xdrs, objp, FHSIZE))
561 return FALSE;
562 return TRUE;
563}
564
565static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp)
566{
567 if (!xdr_u_int(xdrs, &objp->fhs_status))
568 return FALSE;
569 switch (objp->fhs_status) {
570 case 0:
571 if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle))
572 return FALSE;
573 break;
574 default:
575 break;
576 }
577 return TRUE;
578}
579
580static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp)
581{
582 if (!xdr_string(xdrs, objp, MNTPATHLEN))
583 return FALSE;
584 return TRUE;
585}
586
587static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp)
588{
589 if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, (unsigned int *) &objp->fhandle3_len, FHSIZE3))
590 return FALSE;
591 return TRUE;
592}
593
594static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp)
595{
596 if (!xdr_fhandle3(xdrs, &objp->fhandle))
597 return FALSE;
598 if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), &(objp->auth_flavours.auth_flavours_len), ~0,
599 sizeof (int), (xdrproc_t) xdr_int))
600 return FALSE;
601 return TRUE;
602}
603
604static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp)
605{
606 if (!xdr_enum(xdrs, (enum_t *) objp))
607 return FALSE;
608 return TRUE;
609}
610
611static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp)
612{
613 if (!xdr_mountstat3(xdrs, &objp->fhs_status))
614 return FALSE;
615 switch (objp->fhs_status) {
616 case MNT_OK:
617 if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo))
618 return FALSE;
619 break;
620 default:
621 break;
622 }
623 return TRUE;
624}
625
626#define MAX_NFSPROT ((nfs_mount_version >= 4) ? 3 : 2)
627
628/*
629 * nfs_mount_version according to the sources seen at compile time.
630 */
631static int nfs_mount_version;
632static int kernel_version;
633
634/*
635 * Unfortunately, the kernel prints annoying console messages
636 * in case of an unexpected nfs mount version (instead of
637 * just returning some error). Therefore we'll have to try
638 * and figure out what version the kernel expects.
639 *
640 * Variables:
641 * KERNEL_NFS_MOUNT_VERSION: kernel sources at compile time
642 * NFS_MOUNT_VERSION: these nfsmount sources at compile time
643 * nfs_mount_version: version this source and running kernel can handle
644 */
645static void
646find_kernel_nfs_mount_version(void)
647{
648 if (kernel_version)
649 return;
650
651 nfs_mount_version = 4; /* default */
652
653 kernel_version = get_linux_version_code();
654 if (kernel_version) {
655 if (kernel_version < KERNEL_VERSION(2,1,32))
656 nfs_mount_version = 1;
657 else if (kernel_version < KERNEL_VERSION(2,2,18) ||
658 (kernel_version >= KERNEL_VERSION(2,3,0) &&
659 kernel_version < KERNEL_VERSION(2,3,99)))
660 nfs_mount_version = 3;
661 /* else v4 since 2.3.99pre4 */
662 }
663}
664
665static struct pmap *
666get_mountport(struct sockaddr_in *server_addr,
667 long unsigned prog,
668 long unsigned version,
669 long unsigned proto,
670 long unsigned port)
671{
672 struct pmaplist *pmap;
673 static struct pmap p = {0, 0, 0, 0};
674
675 server_addr->sin_port = PMAPPORT;
676 pmap = pmap_getmaps(server_addr);
677
678 if (version > MAX_NFSPROT)
679 version = MAX_NFSPROT;
680 if (!prog)
681 prog = MOUNTPROG;
682 p.pm_prog = prog;
683 p.pm_vers = version;
684 p.pm_prot = proto;
685 p.pm_port = port;
686
687 while (pmap) {
688 if (pmap->pml_map.pm_prog != prog)
689 goto next;
690 if (!version && p.pm_vers > pmap->pml_map.pm_vers)
691 goto next;
692 if (version > 2 && pmap->pml_map.pm_vers != version)
693 goto next;
694 if (version && version <= 2 && pmap->pml_map.pm_vers > 2)
695 goto next;
696 if (pmap->pml_map.pm_vers > MAX_NFSPROT ||
697 (proto && p.pm_prot && pmap->pml_map.pm_prot != proto) ||
698 (port && pmap->pml_map.pm_port != port))
699 goto next;
700 memcpy(&p, &pmap->pml_map, sizeof(p));
701next:
702 pmap = pmap->pml_next;
703 }
704 if (!p.pm_vers)
705 p.pm_vers = MOUNTVERS;
706 if (!p.pm_port)
707 p.pm_port = MOUNTPORT;
708 if (!p.pm_prot)
709 p.pm_prot = IPPROTO_TCP;
710 return &p;
711}
712
713static int daemonize(void)
714{
715 int fd;
716 int pid = fork();
717 if (pid < 0) /* error */
718 return -errno;
719 if (pid > 0) /* parent */
720 return 0;
721 /* child */
722 fd = xopen(bb_dev_null, O_RDWR);
723 dup2(fd, 0);
724 dup2(fd, 1);
725 dup2(fd, 2);
726 if (fd > 2) close(fd);
727 setsid();
728 openlog(applet_name, LOG_PID, LOG_DAEMON);
729 logmode = LOGMODE_SYSLOG;
730 return 1;
731}
732
733// TODO
734static inline int we_saw_this_host_before(const char *hostname)
735{
736 return 0;
737}
738
739/* RPC strerror analogs are terminally idiotic:
740 * *mandatory* prefix and \n at end.
741 * This hopefully helps. Usage:
742 * error_msg_rpc(clnt_*error*(" ")) */
743static void error_msg_rpc(const char *msg)
744{
745 int len;
746 while (msg[0] == ' ' || msg[0] == ':') msg++;
747 len = strlen(msg);
748 while (len && msg[len-1] == '\n') len--;
749 bb_error_msg("%.*s", len, msg);
750}
751
752// NB: mp->xxx fields may be trashed on exit
753static int nfsmount(struct mntent *mp, int vfsflags, char *filteropts)
754{
755 CLIENT *mclient;
756 char *hostname;
757 char *pathname;
758 char *mounthost;
759 struct nfs_mount_data data;
760 char *opt;
761 struct hostent *hp;
762 struct sockaddr_in server_addr;
763 struct sockaddr_in mount_server_addr;
764 int msock, fsock;
765 union {
766 struct fhstatus nfsv2;
767 struct mountres3 nfsv3;
768 } status;
769 int daemonized;
770 char *s;
771 int port;
772 int mountport;
773 int proto;
774 int bg;
775 int soft;
776 int intr;
777 int posix;
778 int nocto;
779 int noac;
780 int nolock;
781 int retry;
782 int tcp;
783 int mountprog;
784 int mountvers;
785 int nfsprog;
786 int nfsvers;
787 int retval;
788
789 find_kernel_nfs_mount_version();
790
791 daemonized = 0;
792 mounthost = NULL;
793 retval = ETIMEDOUT;
794 msock = fsock = -1;
795 mclient = NULL;
796
797 /* NB: hostname, mounthost, filteropts must be free()d prior to return */
798
799 filteropts = xstrdup(filteropts); /* going to trash it later... */
800
801 hostname = xstrdup(mp->mnt_fsname);
802 /* mount_main() guarantees that ':' is there */
803 s = strchr(hostname, ':');
804 pathname = s + 1;
805 *s = '\0';
806 /* Ignore all but first hostname in replicated mounts
807 until they can be fully supported. (mack@sgi.com) */
808 s = strchr(hostname, ',');
809 if (s) {
810 *s = '\0';
811 bb_error_msg("warning: multiple hostnames not supported");
812 }
813
814 server_addr.sin_family = AF_INET;
815 if (!inet_aton(hostname, &server_addr.sin_addr)) {
816 hp = gethostbyname(hostname);
817 if (hp == NULL) {
818 bb_herror_msg("%s", hostname);
819 goto fail;
820 }
821 if (hp->h_length > sizeof(struct in_addr)) {
822 bb_error_msg("got bad hp->h_length");
823 hp->h_length = sizeof(struct in_addr);
824 }
825 memcpy(&server_addr.sin_addr,
826 hp->h_addr, hp->h_length);
827 }
828
829 memcpy(&mount_server_addr, &server_addr, sizeof(mount_server_addr));
830
831 /* add IP address to mtab options for use when unmounting */
832
833 if (!mp->mnt_opts) { /* TODO: actually mp->mnt_opts is never NULL */
834 mp->mnt_opts = xasprintf("addr=%s", inet_ntoa(server_addr.sin_addr));
835 } else {
836 char *tmp = xasprintf("%s%saddr=%s", mp->mnt_opts,
837 mp->mnt_opts[0] ? "," : "",
838 inet_ntoa(server_addr.sin_addr));
839 free(mp->mnt_opts);
840 mp->mnt_opts = tmp;
841 }
842
843 /* Set default options.
844 * rsize/wsize (and bsize, for ver >= 3) are left 0 in order to
845 * let the kernel decide.
846 * timeo is filled in after we know whether it'll be TCP or UDP. */
847 memset(&data, 0, sizeof(data));
848 data.retrans = 3;
849 data.acregmin = 3;
850 data.acregmax = 60;
851 data.acdirmin = 30;
852 data.acdirmax = 60;
853 data.namlen = NAME_MAX;
854
855 bg = 0;
856 soft = 0;
857 intr = 0;
858 posix = 0;
859 nocto = 0;
860 nolock = 0;
861 noac = 0;
862 retry = 10000; /* 10000 minutes ~ 1 week */
863 tcp = 0;
864
865 mountprog = MOUNTPROG;
866 mountvers = 0;
867 port = 0;
868 mountport = 0;
869 nfsprog = 100003;
870 nfsvers = 0;
871
872 /* parse options */
873
874 for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
875 char *opteq = strchr(opt, '=');
876 if (opteq) {
877 const char *const options[] = {
878 /* 0 */ "rsize",
879 /* 1 */ "wsize",
880 /* 2 */ "timeo",
881 /* 3 */ "retrans",
882 /* 4 */ "acregmin",
883 /* 5 */ "acregmax",
884 /* 6 */ "acdirmin",
885 /* 7 */ "acdirmax",
886 /* 8 */ "actimeo",
887 /* 9 */ "retry",
888 /* 10 */ "port",
889 /* 11 */ "mountport",
890 /* 12 */ "mounthost",
891 /* 13 */ "mountprog",
892 /* 14 */ "mountvers",
893 /* 15 */ "nfsprog",
894 /* 16 */ "nfsvers",
895 /* 17 */ "vers",
896 /* 18 */ "proto",
897 /* 19 */ "namlen",
898 /* 20 */ "addr",
899 NULL
900 };
901 int val = xatoi_u(opteq + 1);
902 *opteq = '\0';
903 switch (index_in_str_array(options, opt)) {
904 case 0: // "rsize"
905 data.rsize = val;
906 break;
907 case 1: // "wsize"
908 data.wsize = val;
909 break;
910 case 2: // "timeo"
911 data.timeo = val;
912 break;
913 case 3: // "retrans"
914 data.retrans = val;
915 break;
916 case 4: // "acregmin"
917 data.acregmin = val;
918 break;
919 case 5: // "acregmax"
920 data.acregmax = val;
921 break;
922 case 6: // "acdirmin"
923 data.acdirmin = val;
924 break;
925 case 7: // "acdirmax"
926 data.acdirmax = val;
927 break;
928 case 8: // "actimeo"
929 data.acregmin = val;
930 data.acregmax = val;
931 data.acdirmin = val;
932 data.acdirmax = val;
933 break;
934 case 9: // "retry"
935 retry = val;
936 break;
937 case 10: // "port"
938 port = val;
939 break;
940 case 11: // "mountport"
941 mountport = val;
942 break;
943 case 12: // "mounthost"
944 mounthost = xstrndup(opteq+1,
945 strcspn(opteq+1," \t\n\r,"));
946 break;
947 case 13: // "mountprog"
948 mountprog = val;
949 break;
950 case 14: // "mountvers"
951 mountvers = val;
952 break;
953 case 15: // "nfsprog"
954 nfsprog = val;
955 break;
956 case 16: // "nfsvers"
957 case 17: // "vers"
958 nfsvers = val;
959 break;
960 case 18: // "proto"
961 if (!strncmp(opteq+1, "tcp", 3))
962 tcp = 1;
963 else if (!strncmp(opteq+1, "udp", 3))
964 tcp = 0;
965 else
966 bb_error_msg("warning: unrecognized proto= option");
967 break;
968 case 19: // "namlen"
969 if (nfs_mount_version >= 2)
970 data.namlen = val;
971 else
972 bb_error_msg("warning: option namlen is not supported\n");
973 break;
974 case 20: // "addr" - ignore
975 break;
976 default:
977 bb_error_msg("unknown nfs mount parameter: %s=%d", opt, val);
978 goto fail;
979 }
980 }
981 else {
982 const char *const options[] = {
983 "bg",
984 "fg",
985 "soft",
986 "hard",
987 "intr",
988 "posix",
989 "cto",
990 "ac",
991 "tcp",
992 "udp",
993 "lock",
994 NULL
995 };
996 int val = 1;
997 if (!strncmp(opt, "no", 2)) {
998 val = 0;
999 opt += 2;
1000 }
1001 switch (index_in_str_array(options, opt)) {
1002 case 0: // "bg"
1003 bg = val;
1004 break;
1005 case 1: // "fg"
1006 bg = !val;
1007 break;
1008 case 2: // "soft"
1009 soft = val;
1010 break;
1011 case 3: // "hard"
1012 soft = !val;
1013 break;
1014 case 4: // "intr"
1015 intr = val;
1016 break;
1017 case 5: // "posix"
1018 posix = val;
1019 break;
1020 case 6: // "cto"
1021 nocto = !val;
1022 break;
1023 case 7: // "ac"
1024 noac = !val;
1025 break;
1026 case 8: // "tcp"
1027 tcp = val;
1028 break;
1029 case 9: // "udp"
1030 tcp = !val;
1031 break;
1032 case 10: // "lock"
1033 if (nfs_mount_version >= 3)
1034 nolock = !val;
1035 else
1036 bb_error_msg("warning: option nolock is not supported");
1037 break;
1038 default:
1039 bb_error_msg("unknown nfs mount option: %s%s", val ? "" : "no", opt);
1040 goto fail;
1041 }
1042 }
1043 }
1044 proto = (tcp) ? IPPROTO_TCP : IPPROTO_UDP;
1045
1046 data.flags = (soft ? NFS_MOUNT_SOFT : 0)
1047 | (intr ? NFS_MOUNT_INTR : 0)
1048 | (posix ? NFS_MOUNT_POSIX : 0)
1049 | (nocto ? NFS_MOUNT_NOCTO : 0)
1050 | (noac ? NFS_MOUNT_NOAC : 0);
1051 if (nfs_mount_version >= 2)
1052 data.flags |= (tcp ? NFS_MOUNT_TCP : 0);
1053 if (nfs_mount_version >= 3)
1054 data.flags |= (nolock ? NFS_MOUNT_NONLM : 0);
1055 if (nfsvers > MAX_NFSPROT || mountvers > MAX_NFSPROT) {
1056 bb_error_msg("NFSv%d not supported", nfsvers);
1057 goto fail;
1058 }
1059 if (nfsvers && !mountvers)
1060 mountvers = (nfsvers < 3) ? 1 : nfsvers;
1061 if (nfsvers && nfsvers < mountvers) {
1062 mountvers = nfsvers;
1063 }
1064
1065 /* Adjust options if none specified */
1066 if (!data.timeo)
1067 data.timeo = tcp ? 70 : 7;
1068
1069 data.version = nfs_mount_version;
1070
1071 if (vfsflags & MS_REMOUNT)
1072 goto do_mount;
1073
1074 /*
1075 * If the previous mount operation on the same host was
1076 * backgrounded, and the "bg" for this mount is also set,
1077 * give up immediately, to avoid the initial timeout.
1078 */
1079 if (bg && we_saw_this_host_before(hostname)) {
1080 daemonized = daemonize(); /* parent or error */
1081 if (daemonized <= 0) { /* parent or error */
1082 retval = -daemonized;
1083 goto ret;
1084 }
1085 }
1086
1087 /* create mount daemon client */
1088 /* See if the nfs host = mount host. */
1089 if (mounthost) {
1090 if (mounthost[0] >= '0' && mounthost[0] <= '9') {
1091 mount_server_addr.sin_family = AF_INET;
1092 mount_server_addr.sin_addr.s_addr = inet_addr(hostname);
1093 } else {
1094 hp = gethostbyname(mounthost);
1095 if (hp == NULL) {
1096 bb_herror_msg("%s", mounthost);
1097 goto fail;
1098 } else {
1099 if (hp->h_length > sizeof(struct in_addr)) {
1100 bb_error_msg("got bad hp->h_length?");
1101 hp->h_length = sizeof(struct in_addr);
1102 }
1103 mount_server_addr.sin_family = AF_INET;
1104 memcpy(&mount_server_addr.sin_addr,
1105 hp->h_addr, hp->h_length);
1106 }
1107 }
1108 }
1109
1110 /*
1111 * The following loop implements the mount retries. When the mount
1112 * times out, and the "bg" option is set, we background ourself
1113 * and continue trying.
1114 *
1115 * The case where the mount point is not present and the "bg"
1116 * option is set, is treated as a timeout. This is done to
1117 * support nested mounts.
1118 *
1119 * The "retry" count specified by the user is the number of
1120 * minutes to retry before giving up.
1121 */
1122 {
1123 struct timeval total_timeout;
1124 struct timeval retry_timeout;
1125 struct pmap* pm_mnt;
1126 time_t t;
1127 time_t prevt;
1128 time_t timeout;
1129
1130 retry_timeout.tv_sec = 3;
1131 retry_timeout.tv_usec = 0;
1132 total_timeout.tv_sec = 20;
1133 total_timeout.tv_usec = 0;
1134 timeout = time(NULL) + 60 * retry;
1135 prevt = 0;
1136 t = 30;
1137retry:
1138 /* be careful not to use too many CPU cycles */
1139 if (t - prevt < 30)
1140 sleep(30);
1141
1142 pm_mnt = get_mountport(&mount_server_addr,
1143 mountprog,
1144 mountvers,
1145 proto,
1146 mountport);
1147 nfsvers = (pm_mnt->pm_vers < 2) ? 2 : pm_mnt->pm_vers;
1148
1149 /* contact the mount daemon via TCP */
1150 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
1151 msock = RPC_ANYSOCK;
1152
1153 switch (pm_mnt->pm_prot) {
1154 case IPPROTO_UDP:
1155 mclient = clntudp_create(&mount_server_addr,
1156 pm_mnt->pm_prog,
1157 pm_mnt->pm_vers,
1158 retry_timeout,
1159 &msock);
1160 if (mclient)
1161 break;
1162 mount_server_addr.sin_port = htons(pm_mnt->pm_port);
1163 msock = RPC_ANYSOCK;
1164 case IPPROTO_TCP:
1165 mclient = clnttcp_create(&mount_server_addr,
1166 pm_mnt->pm_prog,
1167 pm_mnt->pm_vers,
1168 &msock, 0, 0);
1169 break;
1170 default:
1171 mclient = 0;
1172 }
1173 if (!mclient) {
1174 if (!daemonized && prevt == 0)
1175 error_msg_rpc(clnt_spcreateerror(" "));
1176 } else {
1177 enum clnt_stat clnt_stat;
1178 /* try to mount hostname:pathname */
1179 mclient->cl_auth = authunix_create_default();
1180
1181 /* make pointers in xdr_mountres3 NULL so
1182 * that xdr_array allocates memory for us
1183 */
1184 memset(&status, 0, sizeof(status));
1185
1186 if (pm_mnt->pm_vers == 3)
1187 clnt_stat = clnt_call(mclient, MOUNTPROC3_MNT,
1188 (xdrproc_t) xdr_dirpath,
1189 (caddr_t) &pathname,
1190 (xdrproc_t) xdr_mountres3,
1191 (caddr_t) &status,
1192 total_timeout);
1193 else
1194 clnt_stat = clnt_call(mclient, MOUNTPROC_MNT,
1195 (xdrproc_t) xdr_dirpath,
1196 (caddr_t) &pathname,
1197 (xdrproc_t) xdr_fhstatus,
1198 (caddr_t) &status,
1199 total_timeout);
1200
1201 if (clnt_stat == RPC_SUCCESS)
1202 goto prepare_kernel_data; /* we're done */
1203 if (errno != ECONNREFUSED) {
1204 error_msg_rpc(clnt_sperror(mclient, " "));
1205 goto fail; /* don't retry */
1206 }
1207 /* Connection refused */
1208 if (!daemonized && prevt == 0) /* print just once */
1209 error_msg_rpc(clnt_sperror(mclient, " "));
1210 auth_destroy(mclient->cl_auth);
1211 clnt_destroy(mclient);
1212 mclient = 0;
1213 close(msock);
1214 }
1215
1216 /* Timeout. We are going to retry... maybe */
1217
1218 if (!bg)
1219 goto fail;
1220 if (!daemonized) {
1221 daemonized = daemonize();
1222 if (daemonized <= 0) { /* parent or error */
1223 retval = -daemonized;
1224 goto ret;
1225 }
1226 }
1227 prevt = t;
1228 t = time(NULL);
1229 if (t >= timeout)
1230 /* TODO error message */
1231 goto fail;
1232
1233 goto retry;
1234 }
1235
1236prepare_kernel_data:
1237
1238 if (nfsvers == 2) {
1239 if (status.nfsv2.fhs_status != 0) {
1240 bb_error_msg("%s:%s failed, reason given by server: %s",
1241 hostname, pathname,
1242 nfs_strerror(status.nfsv2.fhs_status));
1243 goto fail;
1244 }
1245 memcpy(data.root.data,
1246 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1247 NFS_FHSIZE);
1248 data.root.size = NFS_FHSIZE;
1249 memcpy(data.old_root.data,
1250 (char *) status.nfsv2.fhstatus_u.fhs_fhandle,
1251 NFS_FHSIZE);
1252 } else {
1253 fhandle3 *my_fhandle;
1254 if (status.nfsv3.fhs_status != 0) {
1255 bb_error_msg("%s:%s failed, reason given by server: %s",
1256 hostname, pathname,
1257 nfs_strerror(status.nfsv3.fhs_status));
1258 goto fail;
1259 }
1260 my_fhandle = &status.nfsv3.mountres3_u.mountinfo.fhandle;
1261 memset(data.old_root.data, 0, NFS_FHSIZE);
1262 memset(&data.root, 0, sizeof(data.root));
1263 data.root.size = my_fhandle->fhandle3_len;
1264 memcpy(data.root.data,
1265 (char *) my_fhandle->fhandle3_val,
1266 my_fhandle->fhandle3_len);
1267
1268 data.flags |= NFS_MOUNT_VER3;
1269 }
1270
1271 /* create nfs socket for kernel */
1272
1273 if (tcp) {
1274 if (nfs_mount_version < 3) {
1275 bb_error_msg("NFS over TCP is not supported");
1276 goto fail;
1277 }
1278 fsock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
1279 } else
1280 fsock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
1281 if (fsock < 0) {
1282 bb_perror_msg("nfs socket");
1283 goto fail;
1284 }
1285 if (bindresvport(fsock, 0) < 0) {
1286 bb_perror_msg("nfs bindresvport");
1287 goto fail;
1288 }
1289 if (port == 0) {
1290 server_addr.sin_port = PMAPPORT;
1291 port = pmap_getport(&server_addr, nfsprog, nfsvers,
1292 tcp ? IPPROTO_TCP : IPPROTO_UDP);
1293 if (port == 0)
1294 port = NFS_PORT;
1295 }
1296 server_addr.sin_port = htons(port);
1297
1298 /* prepare data structure for kernel */
1299
1300 data.fd = fsock;
1301 memcpy((char *) &data.addr, (char *) &server_addr, sizeof(data.addr));
1302 strncpy(data.hostname, hostname, sizeof(data.hostname));
1303
1304 /* clean up */
1305
1306 auth_destroy(mclient->cl_auth);
1307 clnt_destroy(mclient);
1308 close(msock);
1309
1310 if (bg) {
1311 /* We must wait until mount directory is available */
1312 struct stat statbuf;
1313 int delay = 1;
1314 while (stat(mp->mnt_dir, &statbuf) == -1) {
1315 if (!daemonized) {
1316 daemonized = daemonize();
1317 if (daemonized <= 0) { /* parent or error */
1318 retval = -daemonized;
1319 goto ret;
1320 }
1321 }
1322 sleep(delay); /* 1, 2, 4, 8, 16, 30, ... */
1323 delay *= 2;
1324 if (delay > 30)
1325 delay = 30;
1326 }
1327 }
1328
1329do_mount: /* perform actual mount */
1330
1331 mp->mnt_type = "nfs";
1332 retval = mount_it_now(mp, vfsflags, (char*)&data);
1333 goto ret;
1334
1335fail: /* abort */
1336
1337 if (msock != -1) {
1338 if (mclient) {
1339 auth_destroy(mclient->cl_auth);
1340 clnt_destroy(mclient);
1341 }
1342 close(msock);
1343 }
1344 if (fsock != -1)
1345 close(fsock);
1346
1347ret:
1348 free(hostname);
1349 free(mounthost);
1350 free(filteropts);
1351 return retval;
1352}
1353
1354#else /* !ENABLE_FEATURE_MOUNT_NFS */
1355
1356/* Never called. Call should be optimized out. */
1357int nfsmount(struct mntent *mp, int vfsflags, char *filteropts);
1358
1359#endif /* !ENABLE_FEATURE_MOUNT_NFS */
1360
1361// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
1362// type detection. Returns 0 for success, nonzero for failure.
1363// NB: mp->xxx fields may be trashed on exit
1364static int singlemount(struct mntent *mp, int ignore_busy)
1365{
1366 int rc = -1, vfsflags;
1367 char *loopFile = 0, *filteropts = 0;
1368 llist_t *fl = 0;
1369 struct stat st;
1370
1371 vfsflags = parse_mount_options(mp->mnt_opts, &filteropts);
1372
1373 // Treat fstype "auto" as unspecified.
1374
1375 if (mp->mnt_type && !strcmp(mp->mnt_type,"auto")) mp->mnt_type = 0;
1376
1377 // Might this be an CIFS filesystem?
1378
1379 if (ENABLE_FEATURE_MOUNT_CIFS &&
1380 (!mp->mnt_type || !strcmp(mp->mnt_type,"cifs")) &&
1381 (mp->mnt_fsname[0]==mp->mnt_fsname[1] && (mp->mnt_fsname[0]=='/' || mp->mnt_fsname[0]=='\\')))
1382 {
1383 struct hostent *he;
1384 char ip[32], *s;
1385
1386 rc = 1;
1387 // Replace '/' with '\' and verify that unc points to "//server/share".
1388
1389 for (s = mp->mnt_fsname; *s; ++s)
1390 if (*s == '/') *s = '\\';
1391
1392 // get server IP
1393
1394 s = strrchr(mp->mnt_fsname, '\\');
1395 if (s == mp->mnt_fsname+1) goto report_error;
1396 *s = 0;
1397 he = gethostbyname(mp->mnt_fsname+2);
1398 *s = '\\';
1399 if (!he) goto report_error;
1400
1401 // Insert ip=... option into string flags. (NOTE: Add IPv6 support.)
1402
1403 sprintf(ip, "ip=%d.%d.%d.%d", he->h_addr[0], he->h_addr[1],
1404 he->h_addr[2], he->h_addr[3]);
1405 parse_mount_options(ip, &filteropts);
1406
1407 // compose new unc '\\server-ip\share'
1408
1409 mp->mnt_fsname = xasprintf("\\\\%s%s", ip+3,
1410 strchr(mp->mnt_fsname+2,'\\'));
1411
1412 // lock is required
1413 vfsflags |= MS_MANDLOCK;
1414
1415 mp->mnt_type = "cifs";
1416 rc = mount_it_now(mp, vfsflags, filteropts);
1417 if (ENABLE_FEATURE_CLEAN_UP) free(mp->mnt_fsname);
1418 goto report_error;
1419 }
1420
1421 // Might this be an NFS filesystem?
1422
1423 if (ENABLE_FEATURE_MOUNT_NFS &&
1424 (!mp->mnt_type || !strcmp(mp->mnt_type,"nfs")) &&
1425 strchr(mp->mnt_fsname, ':') != NULL)
1426 {
1427 rc = nfsmount(mp, vfsflags, filteropts);
1428 goto report_error;
1429 }
1430
1431 // Look at the file. (Not found isn't a failure for remount, or for
1432 // a synthetic filesystem like proc or sysfs.)
1433
1434 if (!lstat(mp->mnt_fsname, &st) && !(vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1435 {
1436 // Do we need to allocate a loopback device for it?
1437
1438 if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
1439 loopFile = bb_simplify_path(mp->mnt_fsname);
1440 mp->mnt_fsname = 0;
1441 switch (set_loop(&(mp->mnt_fsname), loopFile, 0)) {
1442 case 0:
1443 case 1:
1444 break;
1445 default:
1446 bb_error_msg( errno == EPERM || errno == EACCES
1447 ? bb_msg_perm_denied_are_you_root
1448 : "cannot setup loop device");
1449 return errno;
1450 }
1451
1452 // Autodetect bind mounts
1453
1454 } else if (S_ISDIR(st.st_mode) && !mp->mnt_type)
1455 vfsflags |= MS_BIND;
1456 }
1457
1458 /* If we know the fstype (or don't need to), jump straight
1459 * to the actual mount. */
1460
1461 if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE)))
1462 rc = mount_it_now(mp, vfsflags, filteropts);
1463
1464 // Loop through filesystem types until mount succeeds or we run out
1465
1466 else {
1467
1468 /* Initialize list of block backed filesystems. This has to be
1469 * done here so that during "mount -a", mounts after /proc shows up
1470 * can autodetect. */
1471
1472 if (!fslist) {
1473 fslist = get_block_backed_filesystems();
1474 if (ENABLE_FEATURE_CLEAN_UP && fslist)
1475 atexit(delete_block_backed_filesystems);
1476 }
1477
1478 for (fl = fslist; fl; fl = fl->link) {
1479 mp->mnt_type = fl->data;
1480 rc = mount_it_now(mp, vfsflags, filteropts);
1481 if (!rc) break;
1482 }
1483 }
1484
1485 // If mount failed, clean up loop file (if any).
1486
1487 if (ENABLE_FEATURE_MOUNT_LOOP && rc && loopFile) {
1488 del_loop(mp->mnt_fsname);
1489 if (ENABLE_FEATURE_CLEAN_UP) {
1490 free(loopFile);
1491 free(mp->mnt_fsname);
1492 }
1493 }
1494
1495report_error:
1496 if (ENABLE_FEATURE_CLEAN_UP) free(filteropts);
1497
1498 if (rc && errno == EBUSY && ignore_busy) rc = 0;
1499 if (rc < 0)
1500 /* perror here sometimes says "mounting ... on ... failed: Success" */
1501 bb_error_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir);
1502
1503 return rc;
1504}
1505
1506// Parse options, if necessary parse fstab/mtab, and call singlemount for
1507// each directory to be mounted.
1508
1509const char must_be_root[] = "you must be root";
1510
1511int mount_main(int argc, char **argv)
1512{
1513 enum { OPT_ALL = 0x10 };
1514
1515 char *cmdopts = xstrdup(""), *fstype=0, *storage_path=0;
1516 char *opt_o;
1517 const char *fstabname;
1518 FILE *fstab;
1519 int i, j, rc = 0;
1520 unsigned opt;
1521 struct mntent mtpair[2], *mtcur = mtpair;
1522 SKIP_DESKTOP(const int nonroot = 0;)
1523 USE_DESKTOP( int nonroot = (getuid() != 0);)
1524
1525 /* parse long options, like --bind and --move. Note that -o option
1526 * and --option are synonymous. Yes, this means --remount,rw works. */
1527
1528 for (i = j = 0; i < argc; i++) {
1529 if (argv[i][0] == '-' && argv[i][1] == '-') {
1530 append_mount_options(&cmdopts, argv[i]+2);
1531 } else argv[j++] = argv[i];
1532 }
1533 argv[j] = 0;
1534 argc = j;
1535
1536 // Parse remaining options
1537
1538 opt = getopt32(argc, argv, "o:t:rwanfvs", &opt_o, &fstype);
1539 if (opt & 0x1) append_mount_options(&cmdopts, opt_o); // -o
1540 //if (opt & 0x2) // -t
1541 if (opt & 0x4) append_mount_options(&cmdopts, "ro"); // -r
1542 if (opt & 0x8) append_mount_options(&cmdopts, "rw"); // -w
1543 //if (opt & 0x10) // -a
1544 if (opt & 0x20) USE_FEATURE_MTAB_SUPPORT(useMtab = 0); // -n
1545 if (opt & 0x40) USE_FEATURE_MTAB_SUPPORT(fakeIt = 1); // -f
1546 //if (opt & 0x80) // -v: verbose (ignore)
1547 //if (opt & 0x100) // -s: sloppy (ignore)
1548 argv += optind;
1549 argc -= optind;
1550
1551 // Three or more non-option arguments? Die with a usage message.
1552
1553 if (argc > 2) bb_show_usage();
1554
1555 // If we have no arguments, show currently mounted filesystems
1556
1557 if (!argc) {
1558 if (!(opt & OPT_ALL)) {
1559 FILE *mountTable = setmntent(bb_path_mtab_file, "r");
1560
1561 if (!mountTable) bb_error_msg_and_die("no %s", bb_path_mtab_file);
1562
1563 while (getmntent_r(mountTable, mtpair, bb_common_bufsiz1,
1564 sizeof(bb_common_bufsiz1)))
1565 {
1566 // Don't show rootfs. FIXME: why??
1567 if (!strcmp(mtpair->mnt_fsname, "rootfs")) continue;
1568
1569 if (!fstype || !strcmp(mtpair->mnt_type, fstype))
1570 printf("%s on %s type %s (%s)\n", mtpair->mnt_fsname,
1571 mtpair->mnt_dir, mtpair->mnt_type,
1572 mtpair->mnt_opts);
1573 }
1574 if (ENABLE_FEATURE_CLEAN_UP) endmntent(mountTable);
1575 return EXIT_SUCCESS;
1576 }
1577 } else storage_path = bb_simplify_path(argv[0]);
1578
1579 // When we have two arguments, the second is the directory and we can
1580 // skip looking at fstab entirely. We can always abspath() the directory
1581 // argument when we get it.
1582
1583 if (argc == 2) {
1584 if (nonroot)
1585 bb_error_msg_and_die(must_be_root);
1586 mtpair->mnt_fsname = argv[0];
1587 mtpair->mnt_dir = argv[1];
1588 mtpair->mnt_type = fstype;
1589 mtpair->mnt_opts = cmdopts;
1590 rc = singlemount(mtpair, 0);
1591 goto clean_up;
1592 }
1593
1594 i = parse_mount_options(cmdopts, 0);
1595 if (nonroot && (i & ~MS_SILENT)) // Non-root users cannot specify flags
1596 bb_error_msg_and_die(must_be_root);
1597
1598 // If we have a shared subtree flag, don't worry about fstab or mtab.
1599
1600 if (ENABLE_FEATURE_MOUNT_FLAGS &&
1601 (i & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)))
1602 {
1603 rc = mount("", argv[0], "", i, "");
1604 if (rc) bb_perror_msg_and_die("%s", argv[0]);
1605 goto clean_up;
1606 }
1607
1608 // Open either fstab or mtab
1609
1610 fstabname = "/etc/fstab";
1611 if (i & MS_REMOUNT) {
1612 fstabname = bb_path_mtab_file;
1613 }
1614 fstab = setmntent(fstabname, "r");
1615 if (!fstab)
1616 bb_perror_msg_and_die("cannot read %s", fstabname);
1617
1618 // Loop through entries until we find what we're looking for.
1619
1620 memset(mtpair, 0, sizeof(mtpair));
1621 for (;;) {
1622 struct mntent *mtnext = (mtcur==mtpair ? mtpair+1 : mtpair);
1623
1624 // Get next fstab entry
1625
1626 if (!getmntent_r(fstab, mtcur, bb_common_bufsiz1
1627 + (mtcur==mtpair ? sizeof(bb_common_bufsiz1)/2 : 0),
1628 sizeof(bb_common_bufsiz1)/2))
1629 {
1630 // Were we looking for something specific?
1631
1632 if (argc) {
1633
1634 // If we didn't find anything, complain.
1635
1636 if (!mtnext->mnt_fsname)
1637 bb_error_msg_and_die("can't find %s in %s",
1638 argv[0], fstabname);
1639
1640 mtcur = mtnext;
1641 if (nonroot) {
1642 // fstab must have "users" or "user"
1643 if (!(parse_mount_options(mtcur->mnt_opts, 0) & MOUNT_USERS))
1644 bb_error_msg_and_die(must_be_root);
1645 }
1646
1647 // Mount the last thing we found.
1648
1649 mtcur->mnt_opts = xstrdup(mtcur->mnt_opts);
1650 append_mount_options(&(mtcur->mnt_opts), cmdopts);
1651 rc = singlemount(mtcur, 0);
1652 free(mtcur->mnt_opts);
1653 }
1654 goto clean_up;
1655 }
1656
1657 /* If we're trying to mount something specific and this isn't it,
1658 * skip it. Note we must match both the exact text in fstab (ala
1659 * "proc") or a full path from root */
1660
1661 if (argc) {
1662
1663 // Is this what we're looking for?
1664
1665 if (strcmp(argv[0], mtcur->mnt_fsname) &&
1666 strcmp(storage_path, mtcur->mnt_fsname) &&
1667 strcmp(argv[0], mtcur->mnt_dir) &&
1668 strcmp(storage_path, mtcur->mnt_dir)) continue;
1669
1670 // Remember this entry. Something later may have overmounted
1671 // it, and we want the _last_ match.
1672
1673 mtcur = mtnext;
1674
1675 // If we're mounting all.
1676
1677 } else {
1678 // Do we need to match a filesystem type?
1679 // TODO: support "-t type1,type2"; "-t notype1,type2"
1680
1681 if (fstype && strcmp(mtcur->mnt_type, fstype)) continue;
1682
1683 // Skip noauto and swap anyway.
1684
1685 if (parse_mount_options(mtcur->mnt_opts, 0)
1686 & (MOUNT_NOAUTO | MOUNT_SWAP)) continue;
1687
1688 // No, mount -a won't mount anything,
1689 // even user mounts, for mere humans.
1690
1691 if (nonroot)
1692 bb_error_msg_and_die(must_be_root);
1693
1694 // Mount this thing.
1695
1696 if (singlemount(mtcur, 1)) {
1697 /* Count number of failed mounts */
1698 rc++;
1699 }
1700 }
1701 }
1702 if (ENABLE_FEATURE_CLEAN_UP) endmntent(fstab);
1703
1704clean_up:
1705
1706 if (ENABLE_FEATURE_CLEAN_UP) {
1707 free(storage_path);
1708 free(cmdopts);
1709 }
1710
1711 return rc;
1712}
diff --git a/util-linux/pivot_root.c b/util-linux/pivot_root.c
new file mode 100644
index 000000000..bd02302c7
--- /dev/null
+++ b/util-linux/pivot_root.c
@@ -0,0 +1,24 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * pivot_root.c - Change root file system. Based on util-linux 2.10s
4 *
5 * busyboxed by Evin Robertson
6 * pivot_root syscall stubbed by Erik Andersen, so it will compile
7 * regardless of the kernel being used.
8 *
9 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
10 */
11#include "busybox.h"
12
13extern int pivot_root(const char * new_root,const char * put_old);
14
15int pivot_root_main(int argc, char **argv)
16{
17 if (argc != 3)
18 bb_show_usage();
19
20 if (pivot_root(argv[1],argv[2]) < 0)
21 bb_perror_msg_and_die("pivot_root");
22
23 return EXIT_SUCCESS;
24}
diff --git a/util-linux/rdate.c b/util-linux/rdate.c
new file mode 100644
index 000000000..12105953d
--- /dev/null
+++ b/util-linux/rdate.c
@@ -0,0 +1,86 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * The Rdate command will ask a time server for the RFC 868 time
4 * and optionally set the system time.
5 *
6 * by Sterling Huxley <sterling@europa.com>
7 *
8 * Licensed under GPL v2 or later, see file License for details.
9*/
10
11#include <sys/types.h>
12#include <sys/socket.h>
13#include <netinet/in.h>
14#include <netdb.h>
15#include <stdio.h>
16#include <string.h>
17#include <time.h>
18#include <stdlib.h>
19#include <unistd.h>
20#include <signal.h>
21
22#include "busybox.h"
23
24
25static const int RFC_868_BIAS = 2208988800UL;
26
27static void socket_timeout(int sig)
28{
29 bb_error_msg_and_die("timeout connecting to time server");
30}
31
32static time_t askremotedate(const char *host)
33{
34 unsigned long nett;
35 struct sockaddr_in s_in;
36 int fd;
37
38 bb_lookup_host(&s_in, host);
39 s_in.sin_port = bb_lookup_port("time", "tcp", 37);
40
41 /* Add a timeout for dead or inaccessible servers */
42 alarm(10);
43 signal(SIGALRM, socket_timeout);
44
45 fd = xconnect_tcp_v4(&s_in);
46
47 if (safe_read(fd, (void *)&nett, 4) != 4) /* read time from server */
48 bb_error_msg_and_die("%s did not send the complete time", host);
49 close(fd);
50
51 /* convert from network byte order to local byte order.
52 * RFC 868 time is the number of seconds
53 * since 00:00 (midnight) 1 January 1900 GMT
54 * the RFC 868 time 2,208,988,800 corresponds to 00:00 1 Jan 1970 GMT
55 * Subtract the RFC 868 time to get Linux epoch
56 */
57
58 return ntohl(nett) - RFC_868_BIAS;
59}
60
61int rdate_main(int argc, char **argv)
62{
63 time_t remote_time;
64 unsigned long flags;
65
66 opt_complementary = "-1";
67 flags = getopt32(argc, argv, "sp");
68
69 remote_time = askremotedate(argv[optind]);
70
71 if ((flags & 2) == 0) {
72 time_t current_time;
73
74 time(&current_time);
75 if (current_time == remote_time)
76 bb_error_msg("current time matches remote time");
77 else
78 if (stime(&remote_time) < 0)
79 bb_perror_msg_and_die("cannot set time of day");
80 }
81
82 if ((flags & 1) == 0)
83 printf("%s", ctime(&remote_time));
84
85 return EXIT_SUCCESS;
86}
diff --git a/util-linux/readprofile.c b/util-linux/readprofile.c
new file mode 100644
index 000000000..dd810f021
--- /dev/null
+++ b/util-linux/readprofile.c
@@ -0,0 +1,236 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * readprofile.c - used to read /proc/profile
4 *
5 * Copyright (C) 1994,1996 Alessandro Rubini (rubini@ipvvis.unipv.it)
6 *
7 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
8 */
9
10/*
11 * 1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
12 * - added Native Language Support
13 * 1999-09-01 Stephane Eranian <eranian@cello.hpl.hp.com>
14 * - 64bit clean patch
15 * 3Feb2001 Andrew Morton <andrewm@uow.edu.au>
16 * - -M option to write profile multiplier.
17 * 2001-11-07 Werner Almesberger <wa@almesberger.net>
18 * - byte order auto-detection and -n option
19 * 2001-11-09 Werner Almesberger <wa@almesberger.net>
20 * - skip step size (index 0)
21 * 2002-03-09 John Levon <moz@compsoc.man.ac.uk>
22 * - make maplineno do something
23 * 2002-11-28 Mads Martin Joergensen +
24 * - also try /boot/System.map-`uname -r`
25 * 2003-04-09 Werner Almesberger <wa@almesberger.net>
26 * - fixed off-by eight error and improved heuristics in byte order detection
27 * 2003-08-12 Nikita Danilov <Nikita@Namesys.COM>
28 * - added -s option; example of use:
29 * "readprofile -s -m /boot/System.map-test | grep __d_lookup | sort -n -k3"
30 *
31 * Taken from util-linux and adapted for busybox by
32 * Paul Mundt <lethal@linux-sh.org>.
33 */
34
35#include "busybox.h"
36#include <sys/utsname.h>
37
38#define S_LEN 128
39
40/* These are the defaults */
41static const char defaultmap[] = "/boot/System.map";
42static const char defaultpro[] = "/proc/profile";
43
44int readprofile_main(int argc, char **argv)
45{
46 FILE *map;
47 const char *mapFile, *proFile, *mult = 0;
48 unsigned long indx = 1;
49 size_t len;
50 uint64_t add0 = 0;
51 unsigned int step;
52 unsigned int *buf, total, fn_len;
53 unsigned long long fn_add, next_add; /* current and next address */
54 char fn_name[S_LEN], next_name[S_LEN]; /* current and next name */
55 char mapline[S_LEN];
56 char mode[8];
57 int optAll = 0, optInfo = 0, optReset = 0;
58 int optVerbose = 0, optNative = 0;
59 int optBins = 0, optSub = 0;
60 int maplineno = 1;
61 int header_printed;
62
63#define next (current^1)
64
65 proFile = defaultpro;
66 mapFile = defaultmap;
67
68 opt_complementary = "nn:aa:bb:ss:ii:rr:vv";
69 getopt32(argc, argv, "M:m:p:nabsirv",
70 &mult, &mapFile, &proFile,
71 &optNative, &optAll, &optBins, &optSub,
72 &optInfo, &optReset, &optVerbose);
73
74 if (optReset || mult) {
75 int multiplier, fd, to_write;
76
77 /*
78 * When writing the multiplier, if the length of the write is
79 * not sizeof(int), the multiplier is not changed
80 */
81 if (mult) {
82 multiplier = xatoi_u(mult);
83 to_write = sizeof(int);
84 } else {
85 multiplier = 0;
86 to_write = 1; /* sth different from sizeof(int) */
87 }
88
89 fd = xopen(defaultpro, O_WRONLY);
90
91 if (full_write(fd, &multiplier, to_write) != to_write)
92 bb_perror_msg_and_die("error writing %s", defaultpro);
93
94 close(fd);
95 return EXIT_SUCCESS;
96 }
97
98 /*
99 * Use an fd for the profiling buffer, to skip stdio overhead
100 */
101 len = INT_MAX;
102 buf = xmalloc_open_read_close(proFile, &len);
103 if (!optNative) {
104 int entries = len/sizeof(*buf);
105 int big = 0, small = 0, i;
106 unsigned *p;
107
108 for (p = buf+1; p < buf+entries; p++) {
109 if (*p & ~0U << (sizeof(*buf)*4))
110 big++;
111 if (*p & ((1 << (sizeof(*buf)*4))-1))
112 small++;
113 }
114 if (big > small) {
115 bb_error_msg("assuming reversed byte order, "
116 "use -n to force native byte order");
117 for (p = buf; p < buf+entries; p++)
118 for (i = 0; i < sizeof(*buf)/2; i++) {
119 unsigned char *b = (unsigned char *) p;
120 unsigned char tmp;
121
122 tmp = b[i];
123 b[i] = b[sizeof(*buf)-i-1];
124 b[sizeof(*buf)-i-1] = tmp;
125 }
126 }
127 }
128
129 step = buf[0];
130 if (optInfo) {
131 printf("Sampling_step: %i\n", step);
132 return EXIT_SUCCESS;
133 }
134
135 total = 0;
136
137 map = xfopen(mapFile, "r");
138
139 while (fgets(mapline, S_LEN, map)) {
140 if (sscanf(mapline, "%llx %s %s", &fn_add, mode, fn_name) != 3)
141 bb_error_msg_and_die("%s(%i): wrong map line",
142 mapFile, maplineno);
143
144 if (!strcmp(fn_name, "_stext")) /* only elf works like this */ {
145 add0 = fn_add;
146 break;
147 }
148 maplineno++;
149 }
150
151 if (!add0)
152 bb_error_msg_and_die("can't find \"_stext\" in %s", mapFile);
153
154 /*
155 * Main loop.
156 */
157 while (fgets(mapline, S_LEN, map)) {
158 unsigned int this = 0;
159
160 if (sscanf(mapline, "%llx %s %s", &next_add, mode, next_name) != 3)
161 bb_error_msg_and_die("%s(%i): wrong map line",
162 mapFile, maplineno);
163
164 header_printed = 0;
165
166 /* ignore any LEADING (before a '[tT]' symbol is found)
167 Absolute symbols */
168 if ((*mode == 'A' || *mode == '?') && total == 0) continue;
169 if (*mode != 'T' && *mode != 't' &&
170 *mode != 'W' && *mode != 'w')
171 break; /* only text is profiled */
172
173 if (indx >= len / sizeof(*buf))
174 bb_error_msg_and_die("profile address out of range. "
175 "Wrong map file?");
176
177 while (indx < (next_add-add0)/step) {
178 if (optBins && (buf[indx] || optAll)) {
179 if (!header_printed) {
180 printf("%s:\n", fn_name);
181 header_printed = 1;
182 }
183 printf("\t%"PRIx64"\t%u\n", (indx - 1)*step + add0, buf[indx]);
184 }
185 this += buf[indx++];
186 }
187 total += this;
188
189 if (optBins) {
190 if (optVerbose || this > 0)
191 printf(" total\t\t\t\t%u\n", this);
192 } else if ((this || optAll) &&
193 (fn_len = next_add-fn_add) != 0) {
194 if (optVerbose)
195 printf("%016llx %-40s %6i %8.4f\n", fn_add,
196 fn_name, this, this/(double)fn_len);
197 else
198 printf("%6i %-40s %8.4f\n",
199 this, fn_name, this/(double)fn_len);
200 if (optSub) {
201 unsigned long long scan;
202
203 for (scan = (fn_add-add0)/step + 1;
204 scan < (next_add-add0)/step; scan++) {
205 unsigned long long addr;
206
207 addr = (scan - 1)*step + add0;
208 printf("\t%#llx\t%s+%#llx\t%u\n",
209 addr, fn_name, addr - fn_add,
210 buf[scan]);
211 }
212 }
213 }
214
215 fn_add = next_add;
216 strcpy(fn_name, next_name);
217
218 maplineno++;
219 }
220
221 /* clock ticks, out of kernel text - probably modules */
222 printf("%6i %s\n", buf[len/sizeof(*buf)-1], "*unknown*");
223
224 /* trailer */
225 if (optVerbose)
226 printf("%016x %-40s %6i %8.4f\n",
227 0, "total", total, total/(double)(fn_add-add0));
228 else
229 printf("%6i %-40s %8.4f\n",
230 total, "total", total/(double)(fn_add-add0));
231
232 fclose(map);
233 free(buf);
234
235 return EXIT_SUCCESS;
236}
diff --git a/util-linux/setarch.c b/util-linux/setarch.c
new file mode 100644
index 000000000..d7e1c0917
--- /dev/null
+++ b/util-linux/setarch.c
@@ -0,0 +1,52 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Linux32/linux64 allows for changing uname emulation.
4 *
5 * Copyright 2002 Andi Kleen, SuSE Labs.
6 *
7 * Licensed under GPL v2 or later, see file License for details.
8*/
9
10#include <stdlib.h>
11#include <unistd.h>
12#include <string.h>
13#include <errno.h>
14#include <stdio.h>
15#include <sys/personality.h>
16
17#include "busybox.h"
18
19int setarch_main(int ATTRIBUTE_UNUSED argc, char **argv)
20{
21 int pers = -1;
22
23 /* Figure out what personality we are supposed to switch to ...
24 * we can be invoked as either:
25 * argv[0],argv[1] -> "setarch","personality"
26 * argv[0] -> "personality"
27 */
28retry:
29 if (argv[0][5] == '6') /* linux64 */
30 pers = PER_LINUX;
31 else if (argv[0][5] == '3') /* linux32 */
32 pers = PER_LINUX32;
33 else if (pers == -1 && argv[1] != NULL) {
34 pers = PER_LINUX32;
35 ++argv;
36 goto retry;
37 }
38
39 /* make user actually gave us something to do */
40 ++argv;
41 if (argv[0] == NULL)
42 bb_show_usage();
43
44 /* Try to set personality */
45 if (personality(pers) >= 0) {
46
47 /* Try to execute the program */
48 execvp(argv[0], argv);
49 }
50
51 bb_perror_msg_and_die("%s", argv[0]);
52}
diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c
new file mode 100644
index 000000000..8434d121c
--- /dev/null
+++ b/util-linux/swaponoff.c
@@ -0,0 +1,77 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini swapon/swapoff implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 *
7 * Licensed under the GPL version 2, see the file LICENSE in this tarball.
8 */
9
10#include "busybox.h"
11#include <mntent.h>
12#include <sys/swap.h>
13
14
15static int swap_enable_disable(char *device)
16{
17 int status;
18 struct stat st;
19
20 xstat(device, &st);
21
22 /* test for holes */
23 if (S_ISREG(st.st_mode))
24 if (st.st_blocks * 512 < st.st_size)
25 bb_error_msg_and_die("swap file has holes");
26
27 if (applet_name[5] == 'n')
28 status = swapon(device, 0);
29 else
30 status = swapoff(device);
31
32 if (status != 0) {
33 bb_perror_msg("%s", device);
34 return 1;
35 }
36
37 return 0;
38}
39
40static int do_em_all(void)
41{
42 struct mntent *m;
43 FILE *f;
44 int err;
45
46 f = setmntent("/etc/fstab", "r");
47 if (f == NULL)
48 bb_perror_msg_and_die("/etc/fstab");
49
50 err = 0;
51 while ((m = getmntent(f)) != NULL)
52 if (strcmp(m->mnt_type, MNTTYPE_SWAP) == 0)
53 err += swap_enable_disable(m->mnt_fsname);
54
55 endmntent(f);
56
57 return err;
58}
59
60#define DO_ALL 0x01
61
62int swap_on_off_main(int argc, char **argv)
63{
64 int ret;
65
66 if (argc == 1)
67 bb_show_usage();
68
69 ret = getopt32(argc, argv, "a");
70 if (ret & DO_ALL)
71 return do_em_all();
72
73 ret = 0;
74 while (*++argv)
75 ret += swap_enable_disable(*argv);
76 return ret;
77}
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
new file mode 100644
index 000000000..4c23f69da
--- /dev/null
+++ b/util-linux/switch_root.c
@@ -0,0 +1,122 @@
1/* vi: set sw=4 ts=4: */
2/* Copyright 2005 Rob Landley <rob@landley.net>
3 *
4 * Switch from rootfs to another filesystem as the root of the mount tree.
5 *
6 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
7 */
8
9#include "busybox.h"
10#include <sys/vfs.h>
11
12
13// Make up for header deficiencies.
14
15#ifndef RAMFS_MAGIC
16#define RAMFS_MAGIC 0x858458f6
17#endif
18
19#ifndef TMPFS_MAGIC
20#define TMPFS_MAGIC 0x01021994
21#endif
22
23#ifndef MS_MOVE
24#define MS_MOVE 8192
25#endif
26
27dev_t rootdev;
28
29// Recursively delete contents of rootfs.
30
31static void delete_contents(char *directory)
32{
33 DIR *dir;
34 struct dirent *d;
35 struct stat st;
36
37 // Don't descend into other filesystems
38 if (lstat(directory, &st) || st.st_dev != rootdev) return;
39
40 // Recursively delete the contents of directories.
41 if (S_ISDIR(st.st_mode)) {
42 if((dir = opendir(directory))) {
43 while ((d = readdir(dir))) {
44 char *newdir=d->d_name;
45
46 // Skip . and ..
47 if(*newdir=='.' && (!newdir[1] || (newdir[1]=='.' && !newdir[2])))
48 continue;
49
50 // Recurse to delete contents
51 newdir = alloca(strlen(directory) + strlen(d->d_name) + 2);
52 sprintf(newdir, "%s/%s", directory, d->d_name);
53 delete_contents(newdir);
54 }
55 closedir(dir);
56
57 // Directory should now be empty. Zap it.
58 rmdir(directory);
59 }
60
61 // It wasn't a directory. Zap it.
62
63 } else unlink(directory);
64}
65
66int switch_root_main(int argc, char *argv[])
67{
68 char *newroot, *console=NULL;
69 struct stat st1, st2;
70 struct statfs stfs;
71
72 // Parse args (-c console)
73
74 opt_complementary = "-2";
75 getopt32(argc, argv, "c:", &console);
76
77 // Change to new root directory and verify it's a different fs.
78
79 newroot=argv[optind++];
80
81 if (chdir(newroot) || lstat(".", &st1) || lstat("/", &st2) ||
82 st1.st_dev == st2.st_dev)
83 {
84 bb_error_msg_and_die("bad newroot %s", newroot);
85 }
86 rootdev=st2.st_dev;
87
88 // Additional sanity checks: we're about to rm -rf /, so be REALLY SURE
89 // we mean it. (I could make this a CONFIG option, but I would get email
90 // from all the people who WILL eat their filesystemss.)
91
92 if (lstat("/init", &st1) || !S_ISREG(st1.st_mode) || statfs("/", &stfs) ||
93 (stfs.f_type != RAMFS_MAGIC && stfs.f_type != TMPFS_MAGIC) ||
94 getpid() != 1)
95 {
96 bb_error_msg_and_die("not rootfs");
97 }
98
99 // Zap everything out of rootdev
100
101 delete_contents("/");
102
103 // Overmount / with newdir and chroot into it. The chdir is needed to
104 // recalculate "." and ".." links.
105
106 if (mount(".", "/", NULL, MS_MOVE, NULL) || chroot(".") || chdir("/"))
107 bb_error_msg_and_die("moving root");
108
109 // If a new console specified, redirect stdin/stdout/stderr to that.
110
111 if (console) {
112 close(0);
113 if(open(console, O_RDWR) < 0)
114 bb_error_msg_and_die("bad console '%s'", console);
115 dup2(0, 1);
116 dup2(0, 2);
117 }
118
119 // Exec real init. (This is why we must be pid 1.)
120 execv(argv[optind], argv+optind);
121 bb_error_msg_and_die("bad init '%s'", argv[optind]);
122}
diff --git a/util-linux/umount.c b/util-linux/umount.c
new file mode 100644
index 000000000..6ba72aed1
--- /dev/null
+++ b/util-linux/umount.c
@@ -0,0 +1,151 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Mini umount implementation for busybox
4 *
5 * Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org>
6 * Copyright (C) 2005 by Rob Landley <rob@landley.net>
7 *
8 * Licensed under GPL version 2, see file LICENSE in this tarball for details.
9 */
10
11#include "busybox.h"
12#include <mntent.h>
13#include <getopt.h>
14
15#define OPTION_STRING "flDnravd"
16#define OPT_FORCE 1
17#define OPT_LAZY 2
18#define OPT_DONTFREELOOP 4
19#define OPT_NO_MTAB 8
20#define OPT_REMOUNT 16
21#define OPT_ALL (ENABLE_FEATURE_UMOUNT_ALL ? 32 : 0)
22
23int umount_main(int argc, char **argv)
24{
25 int doForce;
26 char path[2*PATH_MAX];
27 struct mntent me;
28 FILE *fp;
29 int status = EXIT_SUCCESS;
30 unsigned opt;
31 struct mtab_list {
32 char *dir;
33 char *device;
34 struct mtab_list *next;
35 } *mtl, *m;
36
37 /* Parse any options */
38
39 opt = getopt32(argc, argv, OPTION_STRING);
40
41 argc -= optind;
42 argv += optind;
43
44 doForce = MAX((opt & OPT_FORCE), (opt & OPT_LAZY));
45
46 /* Get a list of mount points from mtab. We read them all in now mostly
47 * for umount -a (so we don't have to worry about the list changing while
48 * we iterate over it, or about getting stuck in a loop on the same failing
49 * entry. Notice that this also naturally reverses the list so that -a
50 * umounts the most recent entries first. */
51
52 m = mtl = 0;
53
54 /* If we're umounting all, then m points to the start of the list and
55 * the argument list should be empty (which will match all). */
56
57 fp = setmntent(bb_path_mtab_file, "r");
58 if (!fp) {
59 if (opt & OPT_ALL)
60 bb_error_msg_and_die("cannot open %s", bb_path_mtab_file);
61 } else {
62 while (getmntent_r(fp, &me, path, sizeof(path))) {
63 m = xmalloc(sizeof(struct mtab_list));
64 m->next = mtl;
65 m->device = xstrdup(me.mnt_fsname);
66 m->dir = xstrdup(me.mnt_dir);
67 mtl = m;
68 }
69 endmntent(fp);
70 }
71
72 /* If we're not umounting all, we need at least one argument. */
73 if (!(opt & OPT_ALL)) {
74 m = 0;
75 if (!argc) bb_show_usage();
76 }
77
78 // Loop through everything we're supposed to umount, and do so.
79 for (;;) {
80 int curstat;
81 char *zapit = *argv;
82
83 // Do we already know what to umount this time through the loop?
84 if (m) safe_strncpy(path, m->dir, PATH_MAX);
85 // For umount -a, end of mtab means time to exit.
86 else if (opt & OPT_ALL) break;
87 // Get next command line argument (and look it up in mtab list)
88 else if (!argc--) break;
89 else {
90 argv++;
91 realpath(zapit, path);
92 for (m = mtl; m; m = m->next)
93 if (!strcmp(path, m->dir) || !strcmp(path, m->device))
94 break;
95 }
96 // If we couldn't find this sucker in /etc/mtab, punt by passing our
97 // command line argument straight to the umount syscall. Otherwise,
98 // umount the directory even if we were given the block device.
99 if (m) zapit = m->dir;
100
101 // Let's ask the thing nicely to unmount.
102 curstat = umount(zapit);
103
104 // Force the unmount, if necessary.
105 if (curstat && doForce) {
106 curstat = umount2(zapit, doForce);
107 if (curstat)
108 bb_error_msg("forced umount of %s failed!", zapit);
109 }
110
111 // If still can't umount, maybe remount read-only?
112 if (curstat && (opt & OPT_REMOUNT) && errno == EBUSY && m) {
113 curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL);
114 bb_error_msg(curstat ? "cannot remount %s read-only" :
115 "%s busy - remounted read-only", m->device);
116 }
117
118 if (curstat) {
119 status = EXIT_FAILURE;
120 bb_perror_msg("cannot umount %s", zapit);
121 } else {
122 /* De-allocate the loop device. This ioctl should be ignored on
123 * any non-loop block devices. */
124 if (ENABLE_FEATURE_MOUNT_LOOP && !(opt & OPT_DONTFREELOOP) && m)
125 del_loop(m->device);
126 if (ENABLE_FEATURE_MTAB_SUPPORT && !(opt & OPT_NO_MTAB) && m)
127 erase_mtab(m->dir);
128 }
129
130 // Find next matching mtab entry for -a or umount /dev
131 // Note this means that "umount /dev/blah" will unmount all instances
132 // of /dev/blah, not just the most recent.
133 while (m && (m = m->next))
134 if ((opt & OPT_ALL) || !strcmp(path, m->device))
135 break;
136 }
137
138 // Free mtab list if necessary
139
140 if (ENABLE_FEATURE_CLEAN_UP) {
141 while (mtl) {
142 m = mtl->next;
143 free(mtl->device);
144 free(mtl->dir);
145 free(mtl);
146 mtl = m;
147 }
148 }
149
150 return status;
151}