diff options
Diffstat (limited to 'util-linux')
-rw-r--r-- | util-linux/cal.c | 390 | ||||
-rw-r--r-- | util-linux/mesg.c | 76 | ||||
-rw-r--r-- | util-linux/renice.c | 148 |
3 files changed, 614 insertions, 0 deletions
diff --git a/util-linux/cal.c b/util-linux/cal.c new file mode 100644 index 0000000..af02608 --- /dev/null +++ b/util-linux/cal.c @@ -0,0 +1,390 @@ +/* vi: set sw=4 ts=4: */ +/* + * Calendar implementation for busybox + * + * See original copyright at the end of this file + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Major size reduction... over 50% (>1.5k) on i386. + */ +//config:config CAL +//config: bool "cal" +//config: default y +//config: help +//config: cal is used to display a monthly calendar. + +//applet:IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_CAL) += cal.o + +/* BB_AUDIT SUSv3 compliant with -j and -y extensions (from util-linux). */ +/* BB_AUDIT BUG: The output of 'cal -j 1752' is incorrect. The upstream + * BB_AUDIT BUG: version in util-linux seems to be broken as well. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/cal.html */ + +//usage:#define cal_trivial_usage +//usage: "[-jy] [[MONTH] YEAR]" +//usage:#define cal_full_usage "\n\n" +//usage: "Display a calendar\n" +//usage: "\n -j Use julian dates" +//usage: "\n -y Display the entire year" + +#include "libbb.h" +#include "unicode.h" + +/* We often use "unsigned" intead of "int", it's easier to div on most CPUs */ + +#define THURSDAY 4 /* for reformation */ +#define SATURDAY 6 /* 1 Jan 1 was a Saturday */ + +#define FIRST_MISSING_DAY 639787 /* 3 Sep 1752 */ +#define NUMBER_MISSING_DAYS 11 /* 11 day correction */ + +#define MAXDAYS 42 /* max slots in a month array */ +#define SPACE -1 /* used in day array */ + +static const unsigned char days_in_month[] ALIGN1 = { + 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static const unsigned char sep1752[] ALIGN1 = { + 1, 2, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30 +}; + +/* Set to 0 or 1 in main */ +#define julian ((unsigned)option_mask32) + +/* leap year -- account for Gregorian reformation in 1752 */ +static int leap_year(unsigned yr) +{ + if (yr <= 1752) + return !(yr % 4); + return (!(yr % 4) && (yr % 100)) || !(yr % 400); +} + +/* number of centuries since 1700, not inclusive */ +#define centuries_since_1700(yr) \ + ((yr) > 1700 ? (yr) / 100 - 17 : 0) + +/* number of centuries since 1700 whose modulo of 400 is 0 */ +#define quad_centuries_since_1700(yr) \ + ((yr) > 1600 ? ((yr) - 1600) / 400 : 0) + +/* number of leap years between year 1 and this year, not inclusive */ +#define leap_years_since_year_1(yr) \ + ((yr) / 4 - centuries_since_1700(yr) + quad_centuries_since_1700(yr)) + +static void center(char *, unsigned, unsigned); +static void day_array(unsigned, unsigned, unsigned *); +static void trim_trailing_spaces_and_print(char *); + +static void blank_string(char *buf, size_t buflen); +static char *build_row(char *p, unsigned *dp); + +#define DAY_LEN 3 /* 3 spaces per day */ +#define J_DAY_LEN (DAY_LEN + 1) +#define WEEK_LEN 20 /* 7 * 3 - one space at the end */ +#define J_WEEK_LEN (WEEK_LEN + 7) +#define HEAD_SEP 2 /* spaces between day headings */ + +int cal_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int cal_main(int argc UNUSED_PARAM, char **argv) +{ + struct tm zero_tm; + time_t now; + unsigned month, year, flags, i; + char *month_names[12]; + /* normal heading: */ + /* "Su Mo Tu We Th Fr Sa" */ + /* -j heading: */ + /* " Su Mo Tu We Th Fr Sa" */ + char day_headings[ENABLE_UNICODE_SUPPORT ? 28 * 6 : 28]; + IF_UNICODE_SUPPORT(char *hp = day_headings;) + char buf[40]; + + init_unicode(); + + flags = getopt32(argv, "jy"); + /* This sets julian = flags & 1: */ + option_mask32 &= 1; + month = 0; + argv += optind; + + if (!argv[0]) { + struct tm *ptm; + + time(&now); + ptm = localtime(&now); + year = ptm->tm_year + 1900; + if (!(flags & 2)) { /* no -y */ + month = ptm->tm_mon + 1; + } + } else { + if (argv[1]) { + if (argv[2]) { + bb_show_usage(); + } + if (!(flags & 2)) { /* no -y */ + month = xatou_range(*argv, 1, 12); + } + argv++; + } + year = xatou_range(*argv, 1, 9999); + } + + blank_string(day_headings, sizeof(day_headings) - 7 + 7*julian); + + i = 0; + do { + zero_tm.tm_mon = i; + /* full month name according to locale */ + strftime(buf, sizeof(buf), "%B", &zero_tm); + month_names[i] = xstrdup(buf); + + if (i < 7) { + zero_tm.tm_wday = i; + /* abbreviated weekday name according to locale */ + strftime(buf, sizeof(buf), "%a", &zero_tm); +#if ENABLE_UNICODE_SUPPORT + if (julian) + *hp++ = ' '; + { + char *two_wchars = unicode_conv_to_printable_fixedwidth(/*NULL,*/ buf, 2); + strcpy(hp, two_wchars); + free(two_wchars); + } + hp += strlen(hp); + *hp++ = ' '; +#else + strncpy(day_headings + i * (3+julian) + julian, buf, 2); +#endif + } + } while (++i < 12); + IF_UNICODE_SUPPORT(hp[-1] = '\0';) + + if (month) { + unsigned row, len, days[MAXDAYS]; + unsigned *dp = days; + char lineout[30]; + + day_array(month, year, dp); + len = sprintf(lineout, "%s %u", month_names[month - 1], year); + printf("%*s%s\n%s\n", + ((7*julian + WEEK_LEN) - len) / 2, "", + lineout, day_headings); + for (row = 0; row < 6; row++) { + build_row(lineout, dp)[0] = '\0'; + dp += 7; + trim_trailing_spaces_and_print(lineout); + } + } else { + unsigned row, which_cal, week_len, days[12][MAXDAYS]; + unsigned *dp; + char lineout[80]; + + sprintf(lineout, "%u", year); + center(lineout, + (WEEK_LEN * 3 + HEAD_SEP * 2) + + julian * (J_WEEK_LEN * 2 + HEAD_SEP + - (WEEK_LEN * 3 + HEAD_SEP * 2)), + 0 + ); + puts("\n"); /* two \n's */ + for (i = 0; i < 12; i++) { + day_array(i + 1, year, days[i]); + } + blank_string(lineout, sizeof(lineout)); + week_len = WEEK_LEN + julian * (J_WEEK_LEN - WEEK_LEN); + for (month = 0; month < 12; month += 3-julian) { + center(month_names[month], week_len, HEAD_SEP); + if (!julian) { + center(month_names[month + 1], week_len, HEAD_SEP); + } + center(month_names[month + 2 - julian], week_len, 0); + printf("\n%s%*s%s", day_headings, HEAD_SEP, "", day_headings); + if (!julian) { + printf("%*s%s", HEAD_SEP, "", day_headings); + } + bb_putchar('\n'); + for (row = 0; row < (6*7); row += 7) { + for (which_cal = 0; which_cal < 3-julian; which_cal++) { + dp = days[month + which_cal] + row; + build_row(lineout + which_cal * (week_len + 2), dp); + } + /* blank_string took care of nul termination. */ + trim_trailing_spaces_and_print(lineout); + } + } + } + + fflush_stdout_and_exit(EXIT_SUCCESS); +} + +/* + * day_array -- + * Fill in an array of 42 integers with a calendar. Assume for a moment + * that you took the (maximum) 6 rows in a calendar and stretched them + * out end to end. You would have 42 numbers or spaces. This routine + * builds that array for any month from Jan. 1 through Dec. 9999. + */ +static void day_array(unsigned month, unsigned year, unsigned *days) +{ + unsigned long temp; + unsigned i; + unsigned day, dw, dm; + + memset(days, SPACE, MAXDAYS * sizeof(int)); + + if ((month == 9) && (year == 1752)) { + /* Assumes the Gregorian reformation eliminates + * 3 Sep. 1752 through 13 Sep. 1752. + */ + unsigned j_offset = julian * 244; + size_t oday = 0; + + do { + days[oday+2] = sep1752[oday] + j_offset; + } while (++oday < sizeof(sep1752)); + + return; + } + + /* day_in_year + * return the 1 based day number within the year + */ + day = 1; + if ((month > 2) && leap_year(year)) { + ++day; + } + + i = month; + while (i) { + day += days_in_month[--i]; + } + + /* day_in_week + * return the 0 based day number for any date from 1 Jan. 1 to + * 31 Dec. 9999. Assumes the Gregorian reformation eliminates + * 3 Sep. 1752 through 13 Sep. 1752. Returns Thursday for all + * missing days. + */ + temp = (long)(year - 1) * 365 + leap_years_since_year_1(year - 1) + day; + if (temp < FIRST_MISSING_DAY) { + dw = ((temp - 1 + SATURDAY) % 7); + } else { + dw = (((temp - 1 + SATURDAY) - NUMBER_MISSING_DAYS) % 7); + } + + if (!julian) { + day = 1; + } + + dm = days_in_month[month]; + if ((month == 2) && leap_year(year)) { + ++dm; + } + + do { + days[dw++] = day++; + } while (--dm); +} + +static void trim_trailing_spaces_and_print(char *s) +{ + char *p = s; + + while (*p) { + ++p; + } + while (p != s) { + --p; + if (!isspace(*p)) { + p[1] = '\0'; + break; + } + } + + puts(s); +} + +static void center(char *str, unsigned len, unsigned separate) +{ + unsigned n = strlen(str); + len -= n; + printf("%*s%*s", (len/2) + n, str, (len/2) + (len % 2) + separate, ""); +} + +static void blank_string(char *buf, size_t buflen) +{ + memset(buf, ' ', buflen); + buf[buflen-1] = '\0'; +} + +static char *build_row(char *p, unsigned *dp) +{ + unsigned col, val, day; + + memset(p, ' ', (julian + DAY_LEN) * 7); + + col = 0; + do { + day = *dp++; + if (day != SPACE) { + if (julian) { + ++p; + if (day >= 100) { + *p = '0'; + p[-1] = (day / 100) + '0'; + day %= 100; + } + } + val = day / 10; + if (val > 0) { + *p = val + '0'; + } + *++p = day % 10 + '0'; + p += 2; + } else { + p += DAY_LEN + julian; + } + } while (++col < 7); + + return p; +} + +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kim Letkeman. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/util-linux/mesg.c b/util-linux/mesg.c new file mode 100644 index 0000000..45c13b8 --- /dev/null +++ b/util-linux/mesg.c @@ -0,0 +1,76 @@ +/* vi: set sw=4 ts=4: */ +/* + * mesg implementation for busybox + * + * Copyright (c) 2002 Manuel Novoa III <mjn3@codepoet.org> + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +//config:config MESG +//config: bool "mesg" +//config: default y +//config: help +//config: Mesg controls access to your terminal by others. It is typically +//config: used to allow or disallow other users to write to your terminal +//config: +//config:config FEATURE_MESG_ENABLE_ONLY_GROUP +//config: bool "Enable writing to tty only by group, not by everybody" +//config: default y +//config: depends on MESG +//config: help +//config: Usually, ttys are owned by group "tty", and "write" tool is +//config: setgid to this group. This way, "mesg y" only needs to enable +//config: "write by owning group" bit in tty mode. +//config: +//config: If you set this option to N, "mesg y" will enable writing +//config: by anybody at all. This is not recommended. + +//applet:IF_MESG(APPLET(mesg, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_MESG) += mesg.o + +//usage:#define mesg_trivial_usage +//usage: "[y|n]" +//usage:#define mesg_full_usage "\n\n" +//usage: "Control write access to your terminal\n" +//usage: " y Allow write access to your terminal\n" +//usage: " n Disallow write access to your terminal" + +#include "libbb.h" + +#if ENABLE_FEATURE_MESG_ENABLE_ONLY_GROUP +#define S_IWGRP_OR_S_IWOTH S_IWGRP +#else +#define S_IWGRP_OR_S_IWOTH (S_IWGRP | S_IWOTH) +#endif + +int mesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mesg_main(int argc UNUSED_PARAM, char **argv) +{ + struct stat sb; + mode_t m; + char c = 0; + + argv++; + + if (argv[0] + && (argv[1] || ((c = argv[0][0]) != 'y' && c != 'n')) + ) { + bb_show_usage(); + } + + if (!isatty(STDIN_FILENO)) + bb_error_msg_and_die("not a tty"); + + xfstat(STDIN_FILENO, &sb, "stderr"); + if (c == 0) { + puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); + return EXIT_SUCCESS; + } + m = (c == 'y') ? sb.st_mode | S_IWGRP_OR_S_IWOTH + : sb.st_mode & ~(S_IWGRP|S_IWOTH); + if (fchmod(STDIN_FILENO, m) != 0) + bb_perror_nomsg_and_die(); + return EXIT_SUCCESS; +} diff --git a/util-linux/renice.c b/util-linux/renice.c new file mode 100644 index 0000000..64213c6 --- /dev/null +++ b/util-linux/renice.c @@ -0,0 +1,148 @@ +/* vi: set sw=4 ts=4: */ +/* + * renice implementation for busybox + * + * Copyright (C) 2005 Manuel Novoa III <mjn3@codepoet.org> + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +/* Notes: + * Setting an absolute priority was obsoleted in SUSv2 and removed + * in SUSv3. However, the common linux version of renice does + * absolute and not relative. So we'll continue supporting absolute, + * although the stdout logging has been removed since both SUSv2 and + * SUSv3 specify that stdout isn't used. + * + * This version is lenient in that it doesn't require any IDs. The + * options -p, -g, and -u are treated as mode switches for the + * following IDs (if any). Multiple switches are allowed. + */ +//config:config RENICE +//config: bool "renice" +//config: default y +//config: help +//config: Renice alters the scheduling priority of one or more running +//config: processes. + +//applet:IF_RENICE(APPLET(renice, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_RENICE) += renice.o + +//usage:#define renice_trivial_usage +//usage: "[-n] PRIORITY [[-p | -g | -u] ID...]..." +//usage:#define renice_full_usage "\n\n" +//usage: "Change scheduling priority of a running process\n" +//usage: "\n -n Add PRIORITY to current nice value" +//usage: "\n Without -n, nice value is set to PRIORITY" +//usage: "\n -p Process ids (default)" +//usage: "\n -g Process group ids" +//usage: "\n -u Process user names" + +#include "libbb.h" +#include <sys/resource.h> + +void BUG_bad_PRIO_PROCESS(void); +void BUG_bad_PRIO_PGRP(void); +void BUG_bad_PRIO_USER(void); + +int renice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int renice_main(int argc UNUSED_PARAM, char **argv) +{ + static const char Xetpriority_msg[] ALIGN1 = "%cetpriority"; + + int retval = EXIT_SUCCESS; + int which = PRIO_PROCESS; /* Default 'which' value. */ + int use_relative = 0; + int adjustment, new_priority; + unsigned who; + char *arg; + + /* Yes, they are not #defines in glibc 2.4! #if won't work */ + if (PRIO_PROCESS < CHAR_MIN || PRIO_PROCESS > CHAR_MAX) + BUG_bad_PRIO_PROCESS(); + if (PRIO_PGRP < CHAR_MIN || PRIO_PGRP > CHAR_MAX) + BUG_bad_PRIO_PGRP(); + if (PRIO_USER < CHAR_MIN || PRIO_USER > CHAR_MAX) + BUG_bad_PRIO_USER(); + + arg = *++argv; + + /* Check if we are using a relative adjustment. */ + if (arg && arg[0] == '-' && arg[1] == 'n') { + use_relative = 1; + if (!arg[2]) + arg = *++argv; + else + arg += 2; + } + + if (!arg) { /* No args? Then show usage. */ + bb_show_usage(); + } + + /* Get the priority adjustment (absolute or relative). */ + adjustment = xatoi_range(arg, INT_MIN/2, INT_MAX/2); + + while ((arg = *++argv) != NULL) { + /* Check for a mode switch. */ + if (arg[0] == '-' && arg[1]) { + static const char opts[] ALIGN1 = { + 'p', 'g', 'u', 0, PRIO_PROCESS, PRIO_PGRP, PRIO_USER + }; + const char *p = strchr(opts, arg[1]); + if (p) { + which = p[4]; + if (!arg[2]) + continue; + arg += 2; + } + } + + /* Process an ID arg. */ + if (which == PRIO_USER) { + struct passwd *p; + p = getpwnam(arg); + if (!p) { + bb_error_msg("unknown user %s", arg); + goto HAD_ERROR; + } + who = p->pw_uid; + } else { + who = bb_strtou(arg, NULL, 10); + if (errno) { + bb_error_msg("invalid number '%s'", arg); + goto HAD_ERROR; + } + } + + /* Get priority to use, and set it. */ + if (use_relative) { + int old_priority; + + errno = 0; /* Needed for getpriority error detection. */ + old_priority = getpriority(which, who); + if (errno) { + bb_perror_msg(Xetpriority_msg, 'g'); + goto HAD_ERROR; + } + + new_priority = old_priority + adjustment; + } else { + new_priority = adjustment; + } + + if (setpriority(which, who, new_priority) == 0) { + continue; + } + + bb_perror_msg(Xetpriority_msg, 's'); + HAD_ERROR: + retval = EXIT_FAILURE; + } + + /* No need to check for errors outputing to stderr since, if it + * was used, the HAD_ERROR label was reached and retval was set. */ + + return retval; +} |